Compare commits

...

526 Commits

Author SHA1 Message Date
Ricki Hirner
b50d1032a6 Resource detection: separate CalDAV/CardDAV detection; handle SocketTimeoutException better; version bump to 2.0.4 2018-09-08 21:47:58 +02:00
Ricki Hirner
a1b04e2b85 Fetch translations from Transifex 2018-08-28 13:40:35 +02:00
Ricki Hirner
f346e7e8ae Version bump to 2.0.3 2018-08-28 13:37:17 +02:00
Ricki Hirner
3789da5199 More fine-grained WebDAV permissions
* service DB: split readOnly into privWriteContent and privUnbind
* collections: use privWriteContent (DAV:write-content privilege) for read-only detection
* AccountActivity: allow collection deletion only when privUnbind (DAV:unbind privilege) is set
2018-08-26 19:58:01 +02:00
Ricki Hirner
b4b420c21d Make debug info text selectable 2018-08-26 18:37:42 +02:00
Ricki Hirner
feb7fa8279 Service detection: ignore HTTP 4xx errors when looking for homesets 2018-08-25 15:58:18 +02:00
Ricki Hirner
11498e5126 Don't offer collection deletion for read-only collections 2018-08-25 15:58:18 +02:00
Ricki Hirner
3b6c41944f Update Kotlin, dokka, build tools, FAQ URL, libs 2018-08-22 13:17:27 +02:00
Ricki Hirner
c1fbeb8de1 Version bump to 2.0.2 2018-08-15 13:09:16 +02:00
Ricki Hirner
633f6d9629 DAVdroid address book sync: only sync address book sub-accounts of current account 2018-08-15 13:07:34 +02:00
Ricki Hirner
04c5c8fa9e Fix crash in resource detection 2018-08-15 12:43:00 +02:00
Ricki Hirner
4f954e330a Fetch translations from Transifex 2018-08-10 21:26:00 +02:00
Ricki Hirner
621900f68f Version bump to 2.0.1 2018-08-10 21:24:17 +02:00
Ricki Hirner
9f2217dca8 Don't keep Acticity context when creating an account 2018-08-09 12:55:26 +02:00
Ricki Hirner
ceb81c8a41 AccountActivity: use AsyncTask instead of own Executor 2018-08-07 19:18:51 +02:00
Ricki Hirner
fc6807f4e8 Really cancel resource detection when dialog is cancelled 2018-08-06 12:32:41 +02:00
Ricki Hirner
288068f23f Use AsyncTask and progress indicator for creating an account 2018-08-06 12:32:05 +02:00
Ricki Hirner
b368a24445 Fetch translations from Transifex; always replace "..." by "…" 2018-08-05 10:59:01 +02:00
Ricki Hirner
6d1be9be46 OSE AboutActivity: take GPL from file and use loader 2018-08-05 10:48:07 +02:00
Ricki Hirner
445a6a231b Collection properties: replace "Copy URL" button by selectable TextView 2018-08-03 14:19:11 +02:00
Ricki Hirner
ce56047da3 Version bump to 2.0 2018-07-30 10:15:59 +02:00
Ricki Hirner
3186b89874 Fetch translations from Transifex 2018-07-28 14:34:09 +02:00
Ricki Hirner
1b0557d4b8 Version bump to 2.0-rc1 2018-07-28 14:29:32 +02:00
Ricki Hirner
5efe1dbed0 Vector drawable: fix Android 4.4 compatibility 2018-07-28 14:29:01 +02:00
Ricki Hirner
d5f1074e30 Fetch translations from Transifex 2018-07-27 16:52:57 +02:00
Ricki Hirner
5e32dc7c91 Fix/improve error handling; bump version to 1.12-beta4 2018-07-27 16:49:42 +02:00
Ricki Hirner
1914269811 Version bump to 1.12-beta3 2018-07-22 11:22:34 +02:00
Ricki Hirner
f1d92b0bfe Fetch translations from Transifex 2018-07-22 11:18:50 +02:00
Ricki Hirner
3c76eb79d6 Use Apache Commons ContextedException instead of own class 2018-07-22 11:15:53 +02:00
Ricki Hirner
86e9cb4ace Rewrite startup strings 2018-07-21 11:07:34 +02:00
Ricki Hirner
3c6ff6e6ac Managed: uses managed profiles feature 2018-07-20 11:47:10 +02:00
Ricki Hirner
1082dc367d Version bump to 1.12-beta2 2018-07-17 13:33:15 +02:00
Ricki Hirner
6e935c433c Collection info: allow copying URL to clipboard 2018-07-17 13:23:59 +02:00
Ricki Hirner
4536378ac9 Collection info fragment 2018-07-17 12:47:46 +02:00
Ricki Hirner
042fb6fefa Remove Espresso tests for now 2018-07-17 12:45:45 +02:00
Ricki Hirner
29faa422ba Account activity: show "Select collections to synchronize" hint when no collections are selected 2018-07-16 18:38:04 +02:00
Ricki Hirner
563737b410 Update to okhttp 3.11 2018-07-16 14:00:49 +02:00
Ricki Hirner
384b91ca77 Update build tools; enable parallel sync of address books authority 2018-07-15 17:10:14 +02:00
Ricki Hirner
1ec933128d Fetch translations from Transifex 2018-07-13 15:06:59 +02:00
Ricki Hirner
f7df046af9 New About activity
* new About activity using AboutLibraries library
* include DAVdroid version and other non-personal information in URL when DAVdroid homepage is opened
  (so that we know what DAVdroid versions are used out there and maybe can provide version-specific help)
2018-07-13 14:57:14 +02:00
Ricki Hirner
1622d6d53e New sync logic with XML streaming
* refactored dav4android to use XML streaming
* refactored collection detection
* refactored sync logic
2018-07-12 00:04:51 +02:00
Ricki Hirner
4ba318fa14 Enable strict mode for debugging; use thread for DB changes in AccountActivity 2018-06-27 12:46:28 +02:00
Ricki Hirner
1eecbad457 Change detection error message 2018-06-24 21:33:51 +02:00
Ricki Hirner
4b9aa376b3 Rename address book accounts correctly when renaming accounts; drop unparsable fields from vCards 2018-06-20 12:38:19 +02:00
Ricki Hirner
9d7c72c3ca Managed: move lambda expressions out of parentheses 2018-06-17 16:55:48 +02:00
Ricki Hirner
f41025d4d8 Version bump to 1.11.5 2018-06-17 16:36:54 +02:00
Ricki Hirner
59c765a6e8 move lambda expressions out of parentheses; use CREATOR-named companion objects for Parcelable 2018-06-17 16:34:45 +02:00
Ricki Hirner
6ff069ac57 Fix lateinit null value in resource detection; update Kotlin and gradle 2018-06-16 15:07:25 +02:00
Ricki Hirner
050f86f020 Version bump to 1.11.4.1-mgd1 2018-06-15 13:34:01 +02:00
Ricki Hirner
e45c8ab1eb Managed: Add login introduction message 2018-06-15 13:33:05 +02:00
Ricki Hirner
dd30677334 Trigger a full calendar sync when past event time limit is changed in account settings 2018-06-14 09:20:55 +02:00
Ricki Hirner
822b49cfcf Don't show contacts permission notification when no address book is selected for synchronization 2018-06-13 17:22:43 +02:00
Ricki Hirner
c667c18199 Version bump to 1.11.4.1 2018-06-12 11:08:51 +02:00
Ricki Hirner
33491336af Version bump to 1.11.4.1-beta1 2018-06-12 00:37:31 +02:00
Ricki Hirner
502a40c179 Collection sync: don't reset "present remotely" flag after enumerating resources 2018-06-12 00:35:39 +02:00
Ricki Hirner
c0bb073a57 Version bump to 1.11.4 2018-06-08 11:50:39 +02:00
Ricki Hirner
a5a3fbb969 Fetch translations from Transifex 2018-06-08 11:50:39 +02:00
Ricki Hirner
9c8219108b Update gradle plugin 2018-06-08 11:50:35 +02:00
Ricki Hirner
f85e435303 Fix crash when collection is deleted 2018-05-30 10:32:45 +02:00
Ricki Hirner
4e4d3b60aa Update copyright 2018-05-28 12:04:43 +02:00
Ricki Hirner
2848f0c466 Add maxOccurs to contacts.xml group membership (allows editing of contacts again) 2018-05-28 11:55:54 +02:00
Ricki Hirner
49512be453 Fetch translations from Transifex 2018-05-28 10:47:49 +02:00
Ricki Hirner
4cae527723 Add group memberships to contacts.xml so that they can be edited with some Contacts apps 2018-05-28 10:46:33 +02:00
Ricki Hirner
0baf10c962 Version bump to 1.11.4-beta2 2018-05-27 16:27:05 +02:00
Ricki Hirner
a8f0c8ea24 Show HTTP request/response in debug info 2018-05-27 16:26:31 +02:00
Ricki Hirner
baa044d61e Use US locale for date in User-Agent 2018-05-27 15:33:34 +02:00
Ricki Hirner
6352113c1e Fix lateinit problem 2018-05-26 12:41:41 +02:00
Ricki Hirner
99c1fd94c5 Use HttpUrl whenever possible
* HttpUrl is the preferred class because we use URLs mainly for okhttp
* don't use URI or String for URLs, if possible
* HttpUrl is not Serializable, so use Parcelable for data classes with HttpUrl

X
2018-05-26 12:30:02 +02:00
Ricki Hirner
4e3e281892 Use weak reference for sync adapter thread lock 2018-05-26 12:29:58 +02:00
Ricki Hirner
5445f2ab72 Don't show InterruptedIOException; tests 2018-05-25 10:56:47 +02:00
Ricki Hirner
c089c3d369 Update to version code 222 (1.11.4-beta1) 2018-05-24 14:09:46 +02:00
Ricki Hirner
6fef958d5f Update ical4android 2018-05-24 14:08:38 +02:00
Ricki Hirner
6d34def40c Integrate adaptive icon 2018-05-23 13:11:29 +02:00
Lokesh Krishna
ed06106c23 Adaptive icon 2018-05-23 12:58:49 +02:00
Ricki Hirner
866841afc0 dav4android update (immutable responses) 2018-05-23 12:50:44 +02:00
Ricki Hirner
8a76167eca Fetch translations from Transifex 2018-05-15 14:21:37 +02:00
Ricki Hirner
8587100853 Collection sync: handle 403 with valid-sync-token precondition 2018-05-14 12:54:26 +02:00
Ricki Hirner
fff7677703 Update build.gradle 2018-05-12 11:26:14 +02:00
Ricki Hirner
a7aded904d Version bump to 1.11.4-beta1 2018-05-11 23:30:27 +02:00
Ricki Hirner
a76cc5a805 ical4android: reduce size of sent VTIMEZONEs 2018-05-11 23:18:18 +02:00
Ricki Hirner
9ec5bd51f5 Version bump to 1.11.3 2018-05-10 12:58:51 +02:00
Ricki Hirner
9c15749257 Version bump to 1.11.3-beta1 2018-05-07 17:55:47 +02:00
Ricki Hirner
faced361d8 Enable Collection Synchronization for CalDAV when past time event limit is disabled 2018-05-07 17:54:35 +02:00
Ricki Hirner
b67e42b91a Version bump to 1.11.2 2018-05-04 11:00:30 +02:00
Ricki Hirner
1012dbfe4b Collection sync: mark skipped entries as locally present 2018-05-01 16:33:47 +02:00
Ricki Hirner
22bd34ce60 Version bump to 1.11.2-beta1 2018-05-01 10:18:28 +02:00
Ricki Hirner
330c2bd49d Improve collection sync for contacts 2018-04-30 12:40:29 +02:00
Ricki Hirner
bf2287550c Collection sync: don't download already available resources 2018-04-29 00:32:25 +02:00
Ricki Hirner
95033a20fd Support collection sync (RFC 6578) for contacts 2018-04-28 23:59:09 +02:00
Ricki Hirner
f8dec15c97 Code cleanup (lint) 2018-04-28 21:21:46 +02:00
Ricki Hirner
3ea1512f95 Fix memory leak in vcard4android 2018-04-27 00:51:22 +02:00
Ricki Hirner
a546823cb9 Add message to local storage error notification 2018-04-26 12:28:56 +02:00
Ricki Hirner
9582e07944 Fetch translations from Transifex 2018-04-26 10:54:20 +02:00
Ricki Hirner
a1b0427bfc Version bump to 1.11.1 2018-04-26 10:51:32 +02:00
Ricki Hirner
4cf4cecf0a Don't throw exception when content provider doesn't return all results; ignore RemoteException on getting contacts sync state 2018-04-26 10:47:46 +02:00
Ricki Hirner
842648d602 Show and use ical4j and okhttp version numbers when possible 2018-04-21 15:01:50 +02:00
Ricki Hirner
4fdcc077f4 Log remote resource info for tasks, too 2018-04-19 08:29:51 +02:00
Ricki Hirner
c0f0f8a83c Update support library and cert4android 2018-04-17 12:14:34 +02:00
Ricki Hirner
c586bab08b Handle exceptions when acquiring task provider 2018-04-15 11:51:11 +02:00
Ricki Hirner
e81ae958aa Treat InterruptedIOException like IOException 2018-04-13 15:23:49 +02:00
Ricki Hirner
051530fa7d Fetch translations from Transifex 2018-04-13 10:24:52 +02:00
Ricki Hirner
628937e109 Version bump to 1.11 2018-04-13 10:18:48 +02:00
Ricki Hirner
cd3662ce43 Update gradle plugin 2018-04-13 09:23:43 +02:00
Ricki Hirner
d694b480c4 Version bump to 1.11-rc1 2018-03-29 14:40:02 +02:00
Ricki Hirner
afc02d5ab5 Update gradle, kotlin, build tools 2018-03-29 14:07:31 +02:00
Ricki Hirner
171cda098a 1.11-beta2 2018-03-26 09:41:07 +02:00
Ricki Hirner
19b660333f Fetch translations from Transifex 2018-03-26 09:37:41 +02:00
Ricki Hirner
e6419ccefc Ask for LOCATION_COARSE permission for WiFi name detection on Android 8.1+ 2018-03-26 09:34:23 +02:00
Ricki Hirner
2a783bef3a Don't re-schedule non-existent master events of deleted exceptions 2018-03-24 23:12:51 +01:00
Ricki Hirner
34c08b299c Improve OpenTasks install message 2018-03-20 12:25:12 +01:00
Ricki Hirner
f2d9221239 Restrict more method names by interfaces 2018-03-16 13:16:04 +01:00
Ricki Hirner
32651978cc Fix sync bugs 2018-03-15 19:36:44 +01:00
Ricki Hirner
437a055c81 Minor fixes 2018-03-15 18:13:53 +01:00
Ricki Hirner
65ef5cd1d9 Use Google repo 2018-03-15 13:10:46 +01:00
Ricki Hirner
cac1339b61 Themeing, minor refactoring 2018-03-15 12:09:27 +01:00
Ricki Hirner
d6c11b7f39 Add "app auto-start permission" startup dialog for specific vendors 2018-03-14 14:54:09 +01:00
Ricki Hirner
4cfb0af588 Tests, minor refactoring 2018-03-12 13:42:17 +01:00
Ricki Hirner
b2ad46e41c Sync error notifications: retry action, lower importance of IOEXceptions 2018-03-09 11:36:43 +01:00
Ricki Hirner
b36731705a Account activity: remove SnackBar message when a read-only address book is selected 2018-03-08 15:19:27 +01:00
Ricki Hirner
4df8aba2ac Show startup fragments only once per AccountActivity lifecycle 2018-03-08 15:18:28 +01:00
Ricki Hirner
5e0ed389c2 Sync logic fix, theming, ProGuard 2018-03-07 23:24:49 +01:00
Ricki Hirner
486c7db99c Update to support library 27.1.0 and use it wherever possible
* Fragment transactions can now be done in onLoadFinished().
2018-03-06 13:58:43 +01:00
Ricki Hirner
58556447f5 Tests 2018-03-05 19:00:59 +01:00
Ricki Hirner
afd614fa19 Further improve notifications 2018-03-05 14:27:08 +01:00
Ricki Hirner
3a69f66ba8 Remove Project Lombok from About
* not used anymore because of Kotlin
* thanks to Project Lombok!
2018-03-05 13:09:30 +01:00
Ricki Hirner
edadc4e260 Remove PermissionsActivity
* asking for permissions is already (and better) done by AccountActivity
2018-03-05 13:04:28 +01:00
Ricki Hirner
0db859f3db Synchronization error messages / notifications 2018-03-05 12:36:48 +01:00
Ricki Hirner
a3a3cf8259 Rewrite sync algorithm, prepare for WebDAV collection sync 2018-02-27 12:24:01 +01:00
Ricki Hirner
c065c48702 Optimize notification icons
* don't show DAVdroid icon unless there's a strong relationship to DAVdroid itself
2018-02-06 12:07:59 +01:00
Ricki Hirner
0f5f2a3331 Fix image loader 2018-01-31 17:13:32 +01:00
Ricki Hirner
d7bf4f95a5 Espresso tests 2018-01-30 14:59:03 +01:00
Ricki Hirner
8c82d21ecc ical4android update 2018-01-27 22:56:50 +01:00
Ricki Hirner
619012e54e Prefer AutoCloseable over Closeable 2018-01-25 15:09:11 +01:00
Ricki Hirner
87ab0ca05b Basic Espresso tests 2018-01-25 15:03:26 +01:00
Ricki Hirner
6f7f35abcc Managed: don't continue to login credentials fragment when there are no settings 2018-01-22 19:09:56 +01:00
Ricki Hirner
3c6f6145f0 Version bump to 1.10.1.1 2018-01-20 17:09:14 +01:00
Ricki Hirner
1fb90762e0 Hotfix: don't clear event colors 2018-01-20 17:08:02 +01:00
Ricki Hirner
3fe1d428a3 Version bump to 1.10.1 2018-01-20 15:24:53 +01:00
Ricki Hirner
c47394b021 Fetch translations from Transifex 2018-01-20 15:23:58 +01:00
Ricki Hirner
faa49350c9 ical4android: work around missing account separation when updating events
* fixes removed eventColor_index fields when there is at least one DAVdroid
  account with enabled calendar colors and at least one account with disabled
  calendar colors
2018-01-20 14:59:52 +01:00
Ricki Hirner
511dde66ad Managed: add login_certificate_alias restriction 2018-01-18 23:35:03 +01:00
Ricki Hirner
c43f016dc7 Update Kotlin 2018-01-18 16:17:08 +01:00
Ricki Hirner
c45e4a1797 Version bump to 1.10 2018-01-18 16:14:23 +01:00
Ricki Hirner
3a734c9e68 Fetch translations from Transifex 2018-01-18 16:13:52 +01:00
Ricki Hirner
e0e4a026e6 Test for client certificates 2018-01-18 16:08:34 +01:00
Ricki Hirner
6f6182c0ce Managed: client certificates 2018-01-18 15:07:35 +01:00
Ricki Hirner
4158ec9aee iCloud, Soldupe 2018-01-16 13:38:52 +01:00
Ricki Hirner
c49333998f Login activity: add padding; sync: re-throw Interrupted(IO)Exception 2018-01-15 21:32:21 +01:00
Ricki Hirner
bc4f4b5dfd Version bump to 1.10-beta 2018-01-15 20:54:34 +01:00
Ricki Hirner
dbd5bde458 Fetch translations from Transifex 2018-01-15 20:52:33 +01:00
Ricki Hirner
be4c680497 Remove unnecessary strings 2018-01-15 20:49:28 +01:00
Ricki Hirner
d7c5ed23b7 Improve sync error notifications
* refactor checking for cancelled sync
* notify on SSLHandshakeException (except when a certificate was rejected by cert4android)
* show exception cause in debug info
2018-01-15 20:41:03 +01:00
Ricki Hirner
25a328a3c4 Login activity
* use TextInputLayout for input fields
* use support library instead of custom EditPassword widget
* improve client certificate UI
2018-01-15 13:58:21 +01:00
Ricki Hirner
dd3d95bdb9 Login with client certificates
* setup UI: login with URL and client certificate
* account settings UI: show either username/password or client certificate alias
* AccountSettings: serve credentials in generalized Credentials objects
* HttpClient: use Credentials (instead of username/password) for authentication
* HttpClient: always use CustomTlsSocketFactory
* CustomTlsSocketFactory: support client certificates
2018-01-13 22:56:33 +01:00
Ricki Hirner
0a47935430 Version bump to 1.9.10 2018-01-03 12:12:18 +01:00
Ricki Hirner
2a83f98f0a Version bump to 1.9.10-beta 2018-01-02 20:26:42 +01:00
Ricki Hirner
2224a6d2ae dav4android update 2018-01-02 20:26:38 +01:00
Ricki Hirner
30968f8ee3 Fetch translations from Transifex 2018-01-02 19:42:27 +01:00
Ricki Hirner
7f9be9a8da Fix DB upgrade logic 2018-01-02 19:25:51 +01:00
Ricki Hirner
a516800f45 Refactoring 2018-01-01 15:12:29 +01:00
Ricki Hirner
0c92b02d73 Do contact provider settings only at address book creation (fixes changed contact visibility at sync) 2017-12-31 13:37:46 +01:00
Ricki Hirner
95354096ab Version bump to 1.9.9 2017-12-27 13:06:22 +01:00
Ricki Hirner
d8a54f823b Fetch translations from Transifex 2017-12-26 13:07:17 +01:00
Ricki Hirner
ceedd218ca Version bump to 1.9.9-beta 2017-12-26 13:07:17 +01:00
Ricki Hirner
1627770103 Update for OpenTasks support
* ical4android update
* use uid field for tasks
* require OpenTasks 1.1.8.2
2017-12-26 13:07:09 +01:00
Ricki Hirner
82b1da5f0d Fix crash 2017-12-18 09:21:42 +01:00
Ricki Hirner
5e70b97942 Version bump to 1.9.8.1 2017-12-16 22:02:36 +01:00
Ricki Hirner
43e216642b Fetch translations from Transifex 2017-12-16 22:02:05 +01:00
Ricki Hirner
4d17bc673f Specify DNS server for dnsjava explicitly 2017-12-16 21:54:33 +01:00
Ricki Hirner
cf24bfa965 Version bump to 1.9.8 2017-12-16 19:08:49 +01:00
Ricki Hirner
3d746e7019 Fetch translations from Transifex 2017-12-16 19:08:49 +01:00
Ricki Hirner
9a30207316 Refactor Loaders, HttpClient
* improve Loader implementation
* use one shared HttpClient singleton
2017-12-16 19:08:49 +01:00
Ricki Hirner
dcb38e89a3 Navigation drawer: add link to manual 2017-12-16 19:08:45 +01:00
Ricki Hirner
2aed1ee97d Version bump to 1.9.7 2017-12-11 20:01:59 +01:00
Ricki Hirner
0a87a15822 Don't rely on LOGIN_ACCOUNTS_CHANGED_ACTION 2017-12-11 18:15:28 +01:00
Ricki Hirner
0bca883d76 Only ask for tasks permission if there's a tasks provider 2017-12-04 23:29:51 +01:00
Ricki Hirner
e4c282cd99 Use email instead of forum for beta feedback 2017-12-03 15:47:27 +01:00
Ricki Hirner
fbc733c16e Fetch translations from Transifex 2017-12-03 15:23:31 +01:00
Ricki Hirner
60d3473f0f Version bump to 1.9.6 2017-12-03 15:17:32 +01:00
Ricki Hirner
0d6d2fcff9 Version bump to 1.9.6-beta 2017-11-30 16:41:29 +01:00
Ricki Hirner
6d4fbd419d Target Android 8.1 (Oreo) 2017-11-30 12:54:18 +01:00
Ricki Hirner
d163cbb882 Define notification channels 2017-11-29 19:17:19 +01:00
Ricki Hirner
47c1b26953 Don't rely on Manifest-declared implicit broadcast to detect when a tasks app is being installed/removed (Android 8 compatibility) 2017-11-29 14:46:21 +01:00
Ricki Hirner
7ac36a64a2 Version bump to 1.9.5 2017-11-28 12:46:34 +01:00
Ricki Hirner
dcd2250349 Cert4android update 2017-11-28 12:44:46 +01:00
Ricki Hirner
6dc4a2d01e Process colors for Webcal calendars, too 2017-11-27 17:54:15 +01:00
Ricki Hirner
b044eab80e Provide title and color in Webcal intent; ical4android update 2017-11-27 17:25:33 +01:00
Ricki Hirner
ad8a264dce Fetch translations from Transifex 2017-11-25 18:49:52 +01:00
Ricki Hirner
f9912456af Version bump to 1.9.4 2017-11-25 18:47:30 +01:00
Ricki Hirner
abcaaf8605 Ask for permissions when account is opened (the permission notification is not always reliable) 2017-11-25 18:46:20 +01:00
Ricki Hirner
47534adad0 Upgrade libraries 2017-11-25 16:46:47 +01:00
Ricki Hirner
502c0db95b Version bump to 1.9.4-beta1 2017-11-13 18:13:21 +01:00
Ricki Hirner
8d81798931 New collection setting: "force read-only"
* collections in AccountActivity: replace long click by action overflow
2017-11-13 18:08:58 +01:00
Ricki Hirner
14563b7ab6 Version bump to 1.9.3 2017-11-12 17:32:16 +01:00
Ricki Hirner
c322ecb774 Fetch translations from Transifex 2017-11-11 21:26:02 +01:00
Ricki Hirner
167317b04f Version bump to 1.9.3-beta1 2017-11-11 21:24:15 +01:00
Ricki Hirner
621c16a100 Dokka KDoc 2017-11-11 20:49:20 +01:00
Ricki Hirner
9ceb2423e7 Raise API level, compatibility, make sync work again
* raise API level to 19 (required by ical4j)
* make HttpClient use Settings to get sync working again
* don't use vector graphics for notification icons (crashes on Android 4.x)
* various fixes and improvements
* library and build tools updates
2017-11-11 20:42:24 +01:00
Ricki Hirner
95c4a96ae3 Refactoring
* refactor Settings and HttpClient
* library updates
2017-11-11 15:38:49 +01:00
Ricki Hirner
045e6ceea9 Managed: license domain restriction, network config cache 2017-11-05 18:41:06 +01:00
Ricki Hirner
512f21ecc3 cert4android: fetch translations 2017-11-04 12:09:09 +01:00
Ricki Hirner
8a90227d19 Version bump to 1.9.2 2017-11-04 12:09:09 +01:00
Ricki Hirner
da5e812ca2 Managed: app name translation, "waiting" message 2017-11-04 12:09:09 +01:00
Ricki Hirner
2c14bd13c8 SDK/build tools 27 2017-11-04 00:45:35 +01:00
Ricki Hirner
918fb1bd48 another 5 minutes wasted life time 2017-10-31 14:01:17 +01:00
Ricki Hirner
f6e1c915da Version bump 2017-10-31 13:41:10 +01:00
Ricki Hirner
eb7ffbee57 German app name 2017-10-31 13:40:33 +01:00
Ricki Hirner
68bc301b7b Fetch translations from Transifex 2017-10-31 13:38:56 +01:00
Ricki Hirner
5d18bfcae9 Change tasks icon, add some view descriptions 2017-10-31 13:36:03 +01:00
Ricki Hirner
8072516b9a Handle exceptions in settings providers 2017-10-31 13:22:28 +01:00
Ricki Hirner
5ed9c66a0a Fetch translations from Transifex 2017-10-31 09:20:12 +01:00
Ricki Hirner
01fba4cd31 ical4android minor bug fix 2017-10-31 09:18:50 +01:00
Ricki Hirner
a8ab6a1b8d lint 2017-10-29 14:16:27 +01:00
Ricki Hirner
f20d193087 Use vector drawable support library for Android <5 2017-10-29 14:11:38 +01:00
Ricki Hirner
4472d43044 Update build tools, gradle, support library 2017-10-28 00:31:49 +02:00
Ricki Hirner
4a201b81ae Version bump to 1.9.1 2017-10-25 20:42:28 +02:00
Ricki Hirner
d54ea0edad Fetch translations from Transifex 2017-10-25 20:38:05 +02:00
Ricki Hirner
909cb96e5f Prevent multiple syncs to be run at the same time for the same account and authority 2017-10-25 18:36:46 +02:00
Ricki Hirner
8f7d377f12 Better handling of contact group method change
* ask for confirmation when group method is changed in account settings activity
* reset address books/force reload when contact group method has changed since last sync
2017-10-25 17:52:03 +02:00
Ricki Hirner
2a01489dcc Add managed configuration activity and network configuration settings provider (QR code / Intent) 2017-10-25 15:21:16 +02:00
Ricki Hirner
93ba407a3f Settings: add force reload 2017-10-25 15:20:32 +02:00
Ricki Hirner
0e4b2820f5 Change homepage to davdroid.com 2017-10-23 14:22:26 +02:00
Ricki Hirner
826578ed89 Resource detection: use related replies to gather collection info, too 2017-10-20 13:53:29 +02:00
Ricki Hirner
20ec2c8989 Version bump to 1.9 2017-10-15 18:14:08 +02:00
Ricki Hirner
d9a0888159 Fetch translations from Transifex 2017-10-15 17:44:48 +02:00
Ricki Hirner
a267a1c5bb Calendars: allow email reminders for events, too 2017-10-15 17:23:07 +02:00
Ricki Hirner
41001579c7 Version bump to 1.9-beta3 2017-10-13 21:36:38 +02:00
Ricki Hirner
19f842421a StartupDialogFragment: Use activity instead of context 2017-10-13 21:35:35 +02:00
Ricki Hirner
b5c8be8c58 Accounts drawer: beta feedback 2017-10-13 20:53:59 +02:00
Ricki Hirner
b43cdd6080 Fetch translations from Transifex 2017-10-13 20:45:13 +02:00
Ricki Hirner
f9d7f05b90 Version bump to 1.9-beta2 2017-10-13 20:42:56 +02:00
Ricki Hirner
af0fb62981 Remove Gitlab CI (OSE only) 2017-10-13 15:01:03 +02:00
Ricki Hirner
84acacf2e0 Minor bug fixes, move beta feedback to navigation drawer 2017-10-13 13:30:01 +02:00
Ricki Hirner
1db0f4985d Managed DAVdroid, settings framework, theming, launcher icons, lib update 2017-10-13 12:24:35 +02:00
Ricki Hirner
9b965a41d6 Assign UID/file name for empty contact even when creating in read-only address book (so that it can be deleted later) 2017-09-25 14:40:34 +02:00
Ricki Hirner
8f115c0552 cert4android: fetch translations from Transifex 2017-09-25 12:08:11 +02:00
Ricki Hirner
0e72810fd0 Fetch translations from Transifex 2017-09-25 12:07:34 +02:00
Ricki Hirner
0db7b2052e Version bump to 1.8.1 2017-09-25 11:56:48 +02:00
Ricki Hirner
7e724a709b Optimize read-only contact notifications 2017-09-25 11:56:10 +02:00
Ricki Hirner
f3e23792bd Version bump to 1.8.1-beta1 2017-09-23 21:25:07 +02:00
Ricki Hirner
a8658890a0 Fetch translations from Transifex 2017-09-23 21:23:37 +02:00
Ricki Hirner
5e8d0a6ae1 Notify on read-only address books
* notify when a read-only address book is selected for synchronization
* notify when local changes have been discarded during sync
2017-09-23 21:10:25 +02:00
Ricki Hirner
c81ba88557 Initial implementation of read-only address books 2017-09-21 23:57:01 +02:00
Ricki Hirner
17c839da17 Fetch translations from Transifex 2017-09-20 22:15:41 +02:00
Ricki Hirner
ca11048f1a Version bump to 1.8 2017-09-20 22:12:55 +02:00
Ricki Hirner
7ecc8c63f3 Reminders: use seconds, too 2017-09-20 22:12:04 +02:00
Ricki Hirner
876fb92ca0 Version bump to 1.8-beta2 2017-09-15 13:29:48 +02:00
Ricki Hirner
a2ead1957a Fetch translations from Transifex 2017-09-15 13:29:22 +02:00
Ricki Hirner
962169b42c Abbreviate too long log messages to reduce OOM errors 2017-09-15 13:20:24 +02:00
Ricki Hirner
ce2ad5b98d Move strings out of global App context 2017-09-15 13:11:07 +02:00
Ricki Hirner
510552639d Change options for sync intervals
* remove 5 and 10 minutes because Android now enforces a minimum interval of 15 min
  (which makes sense in terms of battery optimization)
* add 30 min
2017-09-14 18:16:54 +02:00
Ricki Hirner
d9a7524c32 ical4j update 2017-09-14 17:29:33 +02:00
Ricki Hirner
853e1649b4 Version bump to 1.8-beta1 2017-09-13 17:22:19 +02:00
Ricki Hirner
ac8b2a31ed Fetch translations from Transifex 2017-09-13 17:21:17 +02:00
Ricki Hirner
55c09e00f2 Tests 2017-09-13 17:17:00 +02:00
Ricki Hirner
d6a63b4bb3 Webcal support in UI 2017-09-13 17:07:41 +02:00
Ricki Hirner
08602a018c database support for subscribed calendars (Webcal feeds)
* resource detection: detect/check subscribed calendars
* database: distinguish between CalDAV calendar and subscribed calendar
2017-09-13 15:23:10 +02:00
Ricki Hirner
be804a3fe8 Version bump to 1.7.3 2017-09-10 20:18:18 +02:00
Ricki Hirner
b4459fc2cf Fetch translations from Transifex 2017-09-10 20:17:31 +02:00
Ricki Hirner
7d0e52e1b9 Make SyncManager Closeable 2017-09-10 19:50:12 +02:00
Ricki Hirner
6ab9e4ca44 Don't allow calendars which don't support VEVENT and/or VTODO to be selected for sync 2017-09-10 14:00:37 +02:00
Ricki Hirner
673765bd32 Upgrade to okhttp/3.9.0 2017-09-10 01:30:53 +02:00
Ricki Hirner
0e01070089 cert4android: don't keep CustomCertManager in memory all the time
* remove static reference to CustomCertManager (and thus a Context)
* HttpClient now wraps OkHttpClient and is Closeable
2017-09-09 22:33:24 +02:00
Ricki Hirner
17514ae584 Update cert4android 2017-09-07 14:25:23 +02:00
Ricki Hirner
bea37580cc Fetch cert4android translations from Transifex 2017-09-01 15:13:07 +02:00
Ricki Hirner
ba0f0bac49 Fetch translations from Transifex 2017-09-01 15:12:35 +02:00
Ricki Hirner
d0a13a289c Version bump to 1.7.2 2017-09-01 15:11:26 +02:00
Ricki Hirner
830488b848 donation popup; ProGuard
* don't show donation popup too often
* ProGuard fixes
2017-08-31 01:03:54 +02:00
Ricki Hirner
434f9f8223 Version bump to 1.7.2-beta1 2017-08-30 21:09:47 +02:00
Ricki Hirner
2fd29aa823 Fetch cert4android translations from Transifex 2017-08-30 21:09:47 +02:00
Ricki Hirner
1cbc6d0483 Fetch translations from Transifex 2017-08-30 21:09:42 +02:00
Ricki Hirner
83563aab32 Make event color support optional (opt-in) 2017-08-30 20:21:36 +02:00
Ricki Hirner
2ed5112da6 Update to Android support library 26.0.1 2017-08-30 12:28:08 +02:00
Ricki Hirner
e7978edbe0 Optimize logging 2017-08-29 18:05:59 +02:00
Ricki Hirner
433588447d Fetch translations from Transifex 2017-08-22 15:17:20 +02:00
Ricki Hirner
1096db490e Fetch cert4android translations from Transifex 2017-08-22 15:15:36 +02:00
Ricki Hirner
d8aebbeea1 Version bump to 1.7.1 2017-08-22 15:14:36 +02:00
Ricki Hirner
ae3b89b685 Add donation startup fragment 2017-08-22 14:56:38 +02:00
Ricki Hirner
787e6bae1d ProGuard: keep ThreeTen; update build tools and Kotlin version 2017-08-22 14:18:31 +02:00
Ricki Hirner
5b1c7e85c7 Fetch translations from Transifex 2017-08-19 12:17:13 +02:00
Ricki Hirner
5bfda85aa1 Version bump to 1.7 2017-08-19 12:15:49 +02:00
Ricki Hirner
4437ca79e7 Fix migration 2017-08-15 16:11:03 +02:00
Ricki Hirner
6958a5da1a Version bump to 1.7-beta1 2017-08-15 15:55:07 +02:00
Ricki Hirner
520f17562e Fetch translations from Transifex 2017-08-15 15:52:46 +02:00
Ricki Hirner
22a81d4aad Update Kotlin, vcard4android 2017-08-15 15:49:50 +02:00
Ricki Hirner
a7652e404b Handle conflict when renaming accounts 2017-08-10 17:39:16 +02:00
Ricki Hirner
ad16a43447 WiFi restriction: allow multiple SSIDs (comma-separated) 2017-08-08 13:27:25 +02:00
Ricki Hirner
de7cce7be0 Add support for event colors 2017-08-07 22:49:51 +02:00
Ricki Hirner
20ccc0f8ca Scroll to external log settings when tapping notification 2017-08-05 15:50:22 +02:00
Ricki Hirner
717dd3d898 Version bump to 1.6.5 (160) 2017-08-05 13:26:16 +02:00
Ricki Hirner
17a6bbee6f Adapt icloud flavor 2017-08-05 13:25:15 +02:00
Ricki Hirner
94b2b81fee Fetch lib translations from Transifex 2017-08-05 13:14:22 +02:00
Ricki Hirner
bca30e8457 Fetch translations from Transifex 2017-08-05 13:13:49 +02:00
Ricki Hirner
423231eb46 Minor optimizations 2017-08-05 13:12:06 +02:00
Ricki Hirner
bacf84aeff Version bump to 1.7-beta1 (159) 2017-08-03 23:51:10 +02:00
Ricki Hirner
a1ce99499b Fix DavResourceFinder 2017-08-03 23:49:51 +02:00
Ricki Hirner
cda4cf1195 Fix device rotate crash bug, cert4android race condition 2017-08-03 20:46:32 +02:00
Ricki Hirner
5872979f72 Rewrite Soldupe flavor to Kotlin 2017-08-03 13:01:35 +02:00
Ricki Hirner
62a01fac60 Fix custom certificate socket factory 2017-08-02 17:58:28 +02:00
Ricki Hirner
cd2d410be5 Remove TextUtils dependency; tests 2017-08-02 17:31:24 +02:00
Ricki Hirner
d3495fd4dc Tests 2017-08-02 16:35:12 +02:00
Ricki Hirner
cf5f9c571d Rewrite last UI classes to Kotlin; allow cancellation of resource detection 2017-08-02 16:23:51 +02:00
Ricki Hirner
748316a419 Rewrite most UI classes to Kotlin 2017-08-01 14:52:49 +02:00
Ricki Hirner
3dce04da42 Fix addAccount authenticator crash 2017-07-31 17:42:36 +02:00
Ricki Hirner
f26464b5ba Rewrite some UI classes to Kotlin 2017-07-31 17:36:37 +02:00
Ricki Hirner
a3f4fd0bb5 Rewrite to Kotlin
* rewrite some UI classes
* move logic from App to CustomCertificates and Logger singletons
2017-07-31 15:30:11 +02:00
Ricki Hirner
1c5c947d0f Allow to remove all WiFi SSID restrictions when "sync only on WiFi" is active 2017-07-30 14:54:02 +02:00
Ricki Hirner
6e5e0efbd5 cert4android: fetch translations from Transifex 2017-07-27 16:50:45 +02:00
Ricki Hirner
c2dc66cea1 Fetch translations from Transifex 2017-07-27 16:49:48 +02:00
Ricki Hirner
941343e34d Version bump to 1.6.4 2017-07-27 16:46:55 +02:00
Ricki Hirner
2ce3268acd cert4android, vcard4android updates 2017-07-27 16:45:42 +02:00
Ricki Hirner
5f513e9264 Version bump to 1.6.4-beta2 2017-07-21 15:46:53 +02:00
Ricki Hirner
fcd38a242d Improve debug info 2017-07-21 14:08:50 +02:00
Ricki Hirner
dfd5a81520 Version bump to 1.6.4-beta1 2017-07-20 17:25:59 +02:00
Ricki Hirner
2138fbf0b1 Some minor fixes 2017-07-20 17:24:52 +02:00
Ricki Hirner
77c3125d05 Rewrite LoginCredentials to Kotlin 2017-07-19 22:05:16 +02:00
Ricki Hirner
90fa5a3687 Port iCloud flavor to Kotlin 2017-07-19 21:56:54 +02:00
Ricki Hirner
60162c176c Fix: SSLSocket doesn't implement Closeable in Android 4.1 2017-07-19 19:49:17 +02:00
Ricki Hirner
ebc821cbab Update copyright 2017-07-19 19:30:57 +02:00
Ricki Hirner
f54c0affbc Remove gplay license check 2017-07-19 19:29:42 +02:00
Ricki Hirner
247fd04f13 Rewrite syncadapter package to Kotlin 2017-07-19 19:04:47 +02:00
Ricki Hirner
83708b6127 Rewrite all remaining classes except syncadapter and ui package 2017-07-16 15:27:17 +02:00
Ricki Hirner
821ff102c3 Rewrite DavService to Kotlin 2017-07-16 01:07:13 +02:00
Ricki Hirner
db6fc1330e Rewrite resource package to Kotlin 2017-07-14 20:57:19 +02:00
Ricki Hirner
b33bf50b49 Rewrite some classes to Kotlin 2017-07-10 21:08:35 +02:00
Ricki Hirner
ed8a2b1e06 Rewrite model package to Kotlin 2017-07-10 01:31:05 +02:00
Ricki Hirner
3df17a0b90 Rewrite log package to Kotlin 2017-07-08 13:10:01 +02:00
Ricki Hirner
0961b2081b Use x86 emulator 2017-07-07 00:13:38 +02:00
Ricki Hirner
9b5be6d993 Fetch translations from Transifex 2017-07-06 12:10:30 +02:00
Ricki Hirner
848dedef0c Version bump to 1.6.3 2017-07-06 12:06:07 +02:00
Ricki Hirner
975932e70e More logging (ical4j) + ProGuard 2017-07-06 12:04:46 +02:00
Ricki Hirner
bfe68f06ec Version bump to 1.6.3-beta2 2017-07-04 15:37:11 +02:00
Ricki Hirner
211600b994 Some fixes
* don't acquire contacts provider client for address book management (would require contacts permission check)
* rename task lists: handle all kinds of Exception
* lib updates
2017-07-04 14:58:36 +02:00
Ricki Hirner
341cd3396d Minor bug/NPE fixes 2017-07-03 20:01:02 +02:00
Ricki Hirner
4ed38df9df GPlay: fix NPE in LicenseCheckSyncPlugin 2017-07-03 19:41:30 +02:00
Ricki Hirner
4e599d2d48 Fetch translations from Transifex 2017-07-03 18:54:35 +02:00
Ricki Hirner
42f0c807b1 Require SDK level 16
In Android < 4.1 (< level 16), android.database.Cursor doesn't implement Closeable,
although it provides close(). Since we now use the Kotlin .use() idiom (which requires
a Closeable) instead of calling close() manually or via Lombok, we need Closeable
Cursors and it's not worth to work around this because Android 4.0.4 is now very old.
2017-07-03 18:45:35 +02:00
Ricki Hirner
b9a555f88c Improve preview release startup fragment 2017-07-02 14:41:25 +02:00
Ricki Hirner
13c7623588 1.6.3-beta1 2017-07-02 14:15:47 +02:00
Ricki Hirner
b1d31694d6 Contacts: use hashCode() hack only for Android 7; problem has been fixed by Android 8 2017-07-02 14:06:33 +02:00
Ricki Hirner
016b67a6f5 vcard4android: Kotlin 2017-06-25 16:05:49 +02:00
Ricki Hirner
55645d7c05 Update gradle plugin 2017-06-21 12:58:51 +02:00
Ricki Hirner
66f08db8c0 SDK/build tools level 26 2017-06-21 00:03:17 +02:00
Ricki Hirner
c2707c4475 Version bump to 1.6.2 2017-06-20 15:16:12 +02:00
Ricki Hirner
b405767623 Update libs; update Commons Lang to 3.6 2017-06-20 15:13:53 +02:00
Ricki Hirner
dc17e80347 License check for GPlay version 2017-06-20 11:50:39 +02:00
Ricki Hirner
fd51954682 Lib updates, okhttp/3.8.1 2017-06-19 17:11:22 +02:00
Ricki Hirner
76d33713ab ical4android: Kotlin 2017-06-17 23:08:19 +02:00
Ricki Hirner
ac8542dc25 Version bump to 1.6.1.1 (151) 2017-06-16 18:56:21 +02:00
Ricki Hirner
aa3d648cef MultiSync: force app-specific passwords in UI 2017-06-16 18:44:53 +02:00
Ricki Hirner
76743b6636 Lib updates 2017-06-16 17:53:50 +02:00
Ricki Hirner
e99082dc98 Fetch translations from Transifex 2017-06-09 16:34:03 +02:00
Ricki Hirner
c054e0bfb5 Version bump to 1.6.1 2017-06-09 16:31:53 +02:00
Ricki Hirner
b2d392ac30 dav4android: Kotlin, cert4android: handle InterruptedException 2017-06-09 00:39:10 +02:00
Ricki Hirner
84cc8be288 Google Play version code 2017-06-05 15:01:12 +02:00
Ricki Hirner
fd2ef0b7b0 Birthdays without years, again 2017-06-05 14:35:13 +02:00
Ricki Hirner
492b4ec741 Fetch translations from Transifex 2017-06-03 19:28:11 +02:00
Ricki Hirner
13304cb995 Version bump to 1.6 2017-06-03 19:26:08 +02:00
Ricki Hirner
5247557872 Improve resource detection
* scan unrequested responses for useful auto-detection information
* cert4android: Kotlin
2017-06-03 19:16:52 +02:00
Ricki Hirner
eb14f03475 Support for birthdays without year 2017-06-02 00:37:27 +02:00
Ricki Hirner
6e60503a22 Remove "ical4android" from iCal PRODID (same format as for VCard) 2017-05-14 13:36:08 +02:00
Ricki Hirner
6541c5d300 okhttp 3.8.0 ProGuard settings 2017-05-14 13:00:29 +02:00
Ricki Hirner
55b915ad3f Fetch translations from Transifex 2017-05-14 12:19:11 +02:00
Ricki Hirner
115a481b30 Version bump to 1.5.2 2017-05-14 12:18:28 +02:00
Ricki Hirner
312a385000 Remove "vcard4android" from VCard PRODID to avoid folding for better compatibility 2017-05-14 12:11:06 +02:00
Ricki Hirner
a51cd1ad21 Upgrade to okhttp/3.8.0 2017-05-14 11:32:09 +02:00
Ricki Hirner
1dee4b0d44 Use UUIDs for newly generated event/task UIDs (RFC 7986 5.3 UID Property) 2017-04-27 13:35:14 +02:00
Ricki Hirner
35d540326d Fetch translations from Transifex 2017-04-25 14:12:11 +02:00
Ricki Hirner
c2bd7016bb Version bump to 1.5.1 2017-04-25 14:10:59 +02:00
Ricki Hirner
35ac80cdaf Use untranslated User-Agent string
* refactoring: don't use global string variables
2017-04-24 22:52:52 +02:00
Ricki Hirner
f167512f74 Check sync conditions for contacts sync, too 2017-04-23 18:09:34 +02:00
Ricki Hirner
109d62936a Remove unnecessary InvalidAccountException 2017-04-22 21:37:08 +02:00
Ricki Hirner
1611f64334 Allow null values for IS_ORGANIZER 2017-04-18 23:53:25 +02:00
Ricki Hirner
edfbdfc6cd README updates 2017-04-18 23:53:21 +02:00
Ricki Hirner
976ddd855b Version bump to 1.5.0.3 2017-04-16 15:51:28 +02:00
Ricki Hirner
c31a47b202 Fetch translations from Transifex 2017-04-16 15:49:22 +02:00
Ricki Hirner
6f171d7b11 Upgrade libraries 2017-04-16 14:31:22 +02:00
Ricki Hirner
78a71b7da7 Add Soldupe signing config 2017-04-11 17:58:15 +02:00
Ricki Hirner
95912d6a9c Branding strings
* HTTP client: use app name as User-Agent
* use string resources for homepage URLs
* MultiSync: add FAQ
2017-04-11 16:23:38 +02:00
Ricki Hirner
9d642d7a49 MultiSync: version bump to 1.5.0.2-cloud1 2017-04-08 20:27:37 +02:00
Ricki Hirner
87186a8b51 Billing: ignore DeadObjectExceptions
* update Android gradle plugin to 2.3.1
* dav4android update: follow redirects on DELETE
2017-04-08 20:24:43 +02:00
Ricki Hirner
b6813df8ba Soldupe branding 2017-04-03 14:41:10 +02:00
Ricki Hirner
74e753db49 MultiSync: show DebugInfo on BillingException 2017-04-03 13:38:16 +02:00
Ricki Hirner
9dc6ba634d Version bump to 1.5.0.2 2017-04-02 19:22:05 +02:00
Ricki Hirner
617e8f77a6 Open DAVdroid main activity when add a "DAVdroid Address book" account is added over Settings 2017-03-30 21:22:46 +02:00
Ricki Hirner
12ead7bea7 Account settings: restart loader after sync interval update
* debug info: add signature
2017-03-29 12:39:26 +02:00
Ricki Hirner
72b4f7aba1 Version bump to 1.5.0.1 2017-03-27 11:42:23 +02:00
Ricki Hirner
fcbd56ab8f Hotfix: don't crash on empty address book displayName 2017-03-27 11:41:27 +02:00
Ricki Hirner
5996aa2e56 Varianten-Strings 2017-03-26 20:09:02 +02:00
Ricki Hirner
3d127eb728 Version bump to 1.5 2017-03-26 19:31:00 +02:00
Ricki Hirner
658f286636 Fetch translations from Transifex 2017-03-26 19:31:00 +02:00
Ricki Hirner
061071b1af Improve address book details in debug info 2017-03-26 19:04:38 +02:00
Ricki Hirner
5070511476 Add more debug information
* power saving status
* permissions
* address book accounts
2017-03-25 20:12:08 +01:00
Ricki Hirner
72a24cd2d7 Enable SSL_RSA_WITH_3DES_EDE_CBC_SHA for all Android versions
* refactor cipher selection
2017-03-25 19:51:11 +01:00
Ricki Hirner
411698e747 Version bump to 1.5-beta1 2017-03-19 20:42:33 +01:00
Ricki Hirner
6cf7f424a8 Multiple address books, segment 2
* migration from old address book to new address book accounts (5 -> 6)
* support renaming of address book accounts
* change address book accounts properly when the main account is renamed
2017-03-19 20:21:43 +01:00
Ricki Hirner
e3670feb29 Support for multiple address books per account
* new account type: "DAVdroid address book", which is assigned to a DAVdroid main account
* stub content provider "Address books", which enumerates all DAVdroid address book accounts and runs contacts sync for them
2017-03-16 19:59:47 +01:00
Ricki Hirner
fb66dc1cd3 Unify action bar icon colors 2017-03-12 13:24:33 +01:00
Ricki Hirner
bc8bd18db4 Fix maven 2017-03-03 13:25:24 +01:00
Ricki Hirner
38d7d50c71 Update translations from Transifex 2017-03-03 12:53:30 +01:00
Ricki Hirner
3dbfcab377 Fix cardview colors 2017-03-03 12:47:31 +01:00
Ricki Hirner
687bf0a597 Update gradle 2017-03-03 12:38:16 +01:00
Ricki Hirner
cb5c24f37e Fix cardview background 2017-03-03 00:14:49 +01:00
Ricki Hirner
1b05435144 Version bump to 1.4.1 2017-03-02 23:43:46 +01:00
Ricki Hirner
e57a1a7c24 Fetch translations from Transifex 2017-03-02 23:43:46 +01:00
Ricki Hirner
5bfdb35cb8 AccountsActivity: show message when global sync is disabled 2017-03-02 23:43:41 +01:00
Ricki Hirner
288ed380c3 Soldupe/MultiSync branding 2017-02-28 14:21:04 +01:00
Ricki Hirner
fb9a699694 Continue Soldupe branding 2017-02-27 20:39:21 +01:00
Ricki Hirner
dd760f5b90 Gradle update to 3.4 2017-02-27 17:36:46 +01:00
Ricki Hirner
a4513f3229 Begin Soldupe branding 2017-02-23 13:24:27 +01:00
Ricki Hirner
e694d4ad11 Update ez-vcard 2017-02-23 11:09:47 +01:00
Ricki Hirner
9e91acbd5c Fetch translations from Transifex 2017-02-17 13:55:36 +01:00
Ricki Hirner
a524eccdc6 Version bump to 1.4.0.3 2017-02-17 13:51:55 +01:00
Ricki Hirner
d0541904a0 Don't use uid2445 column on Android <4.2; alarm ACTION: compare only value (ignore parameters) 2017-02-17 09:55:01 +01:00
Ricki Hirner
4e2b8b9202 Version bump to 1.4.0.2 2017-02-12 18:59:05 +01:00
Ricki Hirner
750984f397 Improve Android 7 workaround behavior in combination with CATEGORIES/VCard4 contact groups 2017-02-12 18:57:45 +01:00
Ricki Hirner
a3ab5c0f0e Retain Events.UID_2445 when preparing events for upload
* move file name/UID generation from SyncManager to LocalContact, LocalEvent, LocalTask
* rename updateFileNameAndUID() to prepareForUpload()
* use random UUID for contacts, UidGenerator with Android device ID for events/tasks
* LocalEvent.prepareForUpload(): use existing UID_2445 if available
2017-02-10 17:56:41 +01:00
Ricki Hirner
5ad4139100 Android 7 workaround: update hash after group membership operations 2017-02-10 16:52:25 +01:00
Ricki Hirner
081df97813 Version bump to 1.4.0.1 2017-02-06 11:57:01 +01:00
Ricki Hirner
a2a80a3986 Android 7 workaround bugfix
* use local version of contact before calculating hash code
* don't stop upload sync if there are deleted contacts
2017-02-06 11:55:18 +01:00
Ricki Hirner
92dd7df51c Version bump to 1.4.0 2017-02-05 17:19:42 +01:00
Ricki Hirner
fcbedd744a Use contact hash codes only on Android 7+ (workaround)
vcard4android: don't hash CATEGORIES, more verbose logging
2017-02-05 17:18:36 +01:00
Ricki Hirner
4a73328350 Implement checksum to check whether DIRTY contacts have "really" changed
* contact data hash code = hash code of data fields and group memberships
* Before every contact sync, all dirty contacts are checked whether they're
  "really dirty" (= data hash code has changed). If they're not, the DIRTY
  flag is reset. Works around Android 7 behavior of setting contacts to DIRTY
  even if onky meta data has been updated (for instance, lastContacted after
  a call or SMS),
* When an "upload" sync is initiated by notifyChange and there are no
  "really dirty" contacts, the sync is ignored.
* contact upload: clearDirty() saves hash code, too
* contact download: create()/update() saves hash code, too
* debugging: sync flags (extras) are now logged
2017-02-01 19:18:50 +01:00
Ricki Hirner
f81c6a782e AccountSettingsActivity: use loader
* use Loader for AccountSettingsActivity sync intervals (fixes Android 7 display "issues")
* SyncManager: allow prepare() to skip synchronization
2017-02-01 01:14:19 +01:00
Ricki Hirner
1fe3937bce Upgrade to okhttp 3.6.0 2017-01-30 22:26:54 +01:00
Ricki Hirner
352e35d40c Version bump to 1.3.8 2017-01-29 20:06:49 +01:00
Ricki Hirner
6c13f791ea Fetch translations from Transifex (fixes crash in Spanish version) 2017-01-29 19:22:47 +01:00
Ricki Hirner
46b1f21393 Add information about current local and remote resource to debug info 2017-01-29 19:13:54 +01:00
Ricki Hirner
ed09c1f986 Upgrade to gradle 3.3 2017-01-29 16:43:51 +01:00
Ricki Hirner
5b8caaaa66 Version bump to 1.3.7.1 2017-01-09 21:27:50 +01:00
Ricki Hirner
f02660aa1f Use isAlwaysSyncable for contacts/calendars again because of buggy Android firmwares 2017-01-09 21:26:41 +01:00
Ricki Hirner
6b0bd2e88d Version bump to 1.3.7 (132) 2017-01-09 00:00:28 +01:00
Ricki Hirner
05011a0b28 Change authentication restriction to domains instead of host names 2017-01-08 19:09:12 +01:00
Ricki Hirner
ad019185ba Delete local contacts when no CardDAV collection is selected 2017-01-06 15:51:44 +01:00
Ricki Hirner
8c91915ff1 Cloud fix 2017-01-01 12:55:23 +01:00
Ricki Hirner
fcf8537db3 Version bump to 1.3.6 2017-01-01 12:43:20 +01:00
Ricki Hirner
16070be0c9 Fetch translations from Transifex 2017-01-01 12:26:43 +01:00
Ricki Hirner
47b7ae0420 Update to ez-vcard 0.10.1
* fix REV and PREF problems
2017-01-01 01:12:27 +01:00
Ricki Hirner
6cde48346e Fix permissions notification
* ical4android: remove ORGANIZER from all VEVENT components if there are not attendees
2016-12-31 14:15:27 +01:00
Ricki Hirner
7248f84c4f AccountSettings version 5: enable/disable OpenTasks by availability (Android 7.1.1 fix)
* better handling of setIsSyncable
2016-12-30 14:20:09 +01:00
Ricki Hirner
d065737bb0 Don't show warning on AccountSettings version updates 2016-12-30 13:50:33 +01:00
Ricki Hirner
5297b0fc3c Update to SDK level 25 2016-12-30 02:58:01 +01:00
Ricki Hirner
1a8612b9e6 Change handling of tasks sync when OpenTasks is not installed
* AccountDetailsFragment: at account creation, enable task sync only when OpenTasks is installed
* PackageChangedReceiver: when packages are (un)installed, check for OpenTasks availability and (de)activate task sync for all accounts accordingly
* LocalTaskList: don't cache OpenTasks availability
* sync_*.xml: don't activate sync by default
2016-12-28 22:11:47 +01:00
Ricki Hirner
33a43f61d2 gradle: use $HOME for signing 2016-12-23 16:42:14 +01:00
Ricki Hirner
6211c9b539 Fetch translations from Transifex 2016-12-23 15:55:50 +01:00
Ricki Hirner
4b52f746a0 Version bump to 1.3.5 2016-12-23 15:49:53 +01:00
Ricki Hirner
7cc402e2dd Address book selection changed: update URL as soon as possible 2016-12-19 18:57:45 +01:00
Ricki Hirner
dc26873430 Update gradle to 3.2.1; ical4android/vcard4android updates 2016-12-18 22:01:46 +01:00
Ricki Hirner
87f1da5a0f Update okhttp to 3.5.0 2016-12-02 15:00:46 +01:00
Ricki Hirner
2eb9c7b883 Log group assignments more verbosely 2016-11-25 21:37:04 +01:00
Ricki Hirner
2acacf2736 Rename account: don't crash when content providers are not accessible 2016-11-17 19:58:08 +01:00
Ricki Hirner
1ce1bd275c Version bump to 1.3.4.1 2016-11-14 18:47:58 +01:00
Ricki Hirner
6e55b44257 Fetch translations from Transifex 2016-11-14 18:41:24 +01:00
Ricki Hirner
be816f2eee Avoid some crashes
* check whether ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATION can be resolved before launching it
* cert4android: don't crash when service can't be bound
2016-11-14 18:38:15 +01:00
Ricki Hirner
0d22ff3e52 Allow renaming of accounts
* allow renaming of accounts
* always open AccountActivity, even if there are no services (so that users can delete the account from within DAVdroid)
2016-11-14 01:12:41 +01:00
Ricki Hirner
194e47ac49 Fetch translations from Transifex 2016-11-13 20:34:28 +01:00
Ricki Hirner
3f276d2abe Update build tools to 25.0.0, fix WiFiManager leak 2016-11-13 20:21:29 +01:00
Ricki Hirner
12565986fd Fetch translations from Transifex
ical4android: fix for events without dtend/duration
2016-11-06 17:36:39 +01:00
Ricki Hirner
02ee844823 Version bump to 1.3.4
* library updates
2016-11-04 11:59:48 +01:00
Ricki Hirner
1091fd1472 Add app-wide HTTP proxy setting 2016-10-30 22:21:11 +01:00
Ricki Hirner
39a0c9dcb0 Versions: -gplay1, -cloud1 2016-10-22 16:08:52 +02:00
Ricki Hirner
3550176f99 Debug info: send inline on Android <4.1 and when creating an attachment doesn't work 2016-10-22 02:05:14 +02:00
Ricki Hirner
2ca8328b7d Version bump to 1.3.3.1 2016-10-21 20:10:18 +02:00
Ricki Hirner
d889d9a200 Fetch translations from Transifex 2016-10-21 20:10:18 +02:00
Ricki Hirner
47258bee3d Library updates
* dav4android: disable compression for GET requests because it may change the ETag
* better logging for ical4j messages
* tests
2016-10-21 10:37:48 +02:00
Ricki Hirner
f2b8977a09 ProGuard update; signing config 2016-10-18 12:30:47 +02:00
Ricki Hirner
e2bb514331 Use string resource for logging file provider authority; vcard4android update 2016-10-17 23:56:45 +02:00
Ricki Hirner
fc3219988e Share debug info: always use attachment
* share debug info: always use attachment (before: send inline if it was small enough)
* use FileProvider for debug info attachment (for Android 7 compatibility)
* dav4android, ical4android fixes
2016-10-17 17:45:59 +02:00
Ricki Hirner
acc7a2bd57 Fetch translations from Transifex 2016-10-14 21:19:56 +02:00
Ricki Hirner
6ba68a331d Version bump to 1.3.3 2016-10-14 20:57:11 +02:00
Ricki Hirner
c17c0aa385 dav4android: always use UTF-8 for Basic/Digest auth credentials 2016-10-13 15:22:50 +02:00
Ricki Hirner
06d7180972 MultiSync SubscribtionActivity: button for "try again" on error; UI fix 2016-10-13 15:22:46 +02:00
Ricki Hirner
9eb1be6de6 MultiSync improvements
* use Loader for license info
* dark action bar for About activity
* version bump to 1.3.2.2-cloud1
2016-10-12 21:03:13 +02:00
Ricki Hirner
e5ce5eff03 MultiSync: ignore IllegalArgumentException on unbindService 2016-10-12 18:58:27 +02:00
Ricki Hirner
5af48bb6ef ical4android: ignore invalid DUE < DTSTART for tasks 2016-10-12 17:03:17 +02:00
Ricki Hirner
644f7ef521 Remove VCard RFC6868 setting (always enabled now; setting not needed for Posteo compatibility anymore) 2016-10-12 16:41:08 +02:00
Ricki Hirner
c4044fa0ad Gitlab CI: install OpenTasks before tests 2016-10-12 13:03:43 +02:00
Ricki Hirner
f0c12ce78a vcard4android: ez-vcard 0.10.0 2016-10-11 23:35:47 +02:00
Ricki Hirner
9bb85866b2 Test adaptions 2016-10-11 00:26:50 +02:00
Ricki Hirner
eb5b35ce56 Switch to JUnit4 2016-10-10 21:03:32 +02:00
Ricki Hirner
9cd3304011 Add Gitlab CI 2016-10-10 20:18:05 +02:00
Ricki Hirner
009e864aa9 Improve tests 2016-10-07 14:39:40 +02:00
Ricki Hirner
d05985c259 Fix NPE in "is refreshing progress bar" 2016-10-07 14:39:35 +02:00
Ricki Hirner
f9d3f94c2d Version bump to 1.3.2.2 2016-10-05 11:15:48 +02:00
Ricki Hirner
81c4ad75f1 Enable verbose logging of allow loggers (for instance, okhttp) / dav4android update 2016-10-04 22:41:52 +02:00
Ricki Hirner
7ea11fe351 Android 4.0/4.1 fixes
* require API level 15 for TransactionTooLargeException
* use SQLite WAL only on API level 16+
* various database access, provider access and UI fixes
2016-10-04 16:12:44 +02:00
Ricki Hirner
37e0848e63 Version bump to 1.3.2 2016-10-03 20:55:42 +02:00
Ricki Hirner
85ed6a52ae Fetch translations from Transifex 2016-10-03 20:43:33 +02:00
Ricki Hirner
3d85d228a1 Avoid "no transaction" exception 2016-10-03 20:11:18 +02:00
Ricki Hirner
847aa6be92 Use an own ISyncPlugin instance per SyncAdapter 2016-10-03 12:13:00 +02:00
Ricki Hirner
41cc5bd5e2 Minimal layout change 2016-10-03 12:12:38 +02:00
Ricki Hirner
1fe2b6d5c3 Show progress bar when synchronization is active 2016-09-26 22:57:45 +02:00
Ricki Hirner
7da10249e2 Increase SEQUENCE only when we're ORGANIZER 2016-09-24 22:23:25 +02:00
Ricki Hirner
a8f1114b9c Query/use CalDAV email address as account name, if available 2016-09-24 21:33:59 +02:00
Ricki Hirner
318f3aad45 MultiSync for Cloud: one-time payment instead of subscription 2016-09-24 15:53:06 +02:00
Ricki Hirner
1fddbc8fad Always increase SEQUENCE 2016-09-23 13:55:45 +02:00
Ricki Hirner
5a9a93e1ae lint: don't keep references to Context in static fields 2016-09-21 21:59:17 +02:00
Ricki Hirner
b430389f46 Version bump to 1.3.1
* some cert4android tests
2016-09-18 17:37:08 +02:00
Ricki Hirner
d73fced009 Import strings from Transifex 2016-09-18 16:51:05 +02:00
Ricki Hirner
decee792ab Always use PROPFIND instead of REPORT addressbook-query 2016-09-18 16:38:41 +02:00
Ricki Hirner
d50b3a551b Add About activity for iCloud flavor 2016-09-18 16:36:11 +02:00
Ricki Hirner
8753e80a13 New icon, show license notification again 2016-09-06 23:07:00 +02:00
Ricki Hirner
cbdce8df8e Reinitialize certificate manager when needed 2016-09-06 21:56:44 +02:00
Ricki Hirner
be5318f2b9 README changes 2016-09-02 12:21:11 +02:00
Ricki Hirner
274ac5289e Fetch translations from Transifex 2016-09-02 12:15:17 +02:00
Ricki Hirner
ce5b64a55c lint optimizations
* permissions: declare AUTHENTICATE_ACCOUNTS, GET_ACCOUNTS and MANAGE_ACCOUNTS only until SDK level 22
* minor optimizations and bug fixes
2016-09-02 11:57:16 +02:00
Ricki Hirner
c6a9e3f7a6 Version bump to 1.3
* vcard4android: fix bug concerning generated formatted postal addresses
2016-09-02 00:56:06 +02:00
Ricki Hirner
27b42f0686 gplay version: remove donation link
Fix icons again
2016-09-02 00:56:00 +02:00
Ricki Hirner
8700d0d893 New launcher logo
* new launcher logo (contributed by Christoph Scheidl)
2016-09-01 22:48:12 +02:00
Ricki Hirner
939ae6a5ed Use cert4android instead of MemorizingTrustManager
* use cert4android instead of MemorizingTrustManager
* new app setting: distrust system certificates
* add network security config to manifest so that user-installed CAs will be accepted in Android 7 again
* update gradle
2016-09-01 22:03:38 +02:00
Ricki Hirner
de4633ae07 iCloud: UI and strings 2016-08-14 20:57:31 +02:00
Ricki Hirner
76c331a68b Navigation drawer, read-only settings 2016-08-14 17:49:18 +02:00
Ricki Hirner
b4ece96a76 White icons for Apple® iCloud®, hallelujah™ 2016-08-14 13:18:45 +02:00
Ricki Hirner
b51a9c2be2 Accept intent extras for LoginActivity 2016-08-13 23:06:28 +02:00
Ricki Hirner
0adacff51b Fetch translations from Transifex 2016-08-06 00:11:40 +02:00
Ricki Hirner
c82150493c Fix OpenTasks regression bug
* version bump to 1.2.3
* enable OpenTasks sync on Android <6 again
2016-08-05 23:17:55 +02:00
Ricki Hirner
9c2b965ac0 Improve HTTP authentication
* use preemptive Basic auth automatically for HTTPS connections
* cache auth parameters (Basic/Digest)
2016-08-05 23:17:32 +02:00
Ricki Hirner
b914a5d8c2 Fetch translations from Transifex 2016-08-02 19:27:14 +02:00
Ricki Hirner
5281bc6ce0 Request ignoring battery optimization
* startup dialog: request to ignore battery optimizations
* remove F-Droid donation startup dialog (only useful for davdroid-ose)
* version bump to 1.2.2
2016-08-02 19:27:07 +02:00
Ricki Hirner
fa4da093cd Avoid sync error when OpenTasks is not installed 2016-08-01 21:49:20 +02:00
Ricki Hirner
1d2692a257 Clean up launcher icon
* clean up launcher icon
* update dependencies
2016-08-01 21:03:21 +02:00
Ricki Hirner
cae67244d3 Basic subscription management
* SDK version 24
* Subscription management and GUI
2016-08-01 20:24:32 +02:00
Ricki Hirner
291f965cd7 iCloud: implement free trial 2016-07-29 15:21:17 +02:00
Ricki Hirner
cbb89ffecb Initial iCloud version
* new gradle configField: useMTM
* new gradle source dir: davdroid (for DAVdroid OSE + DAVdroid variants)
* move strings and default login fragment to davdroid source dir
* iCloud AndroidManifest: add billing permission and SubscriptionActivity
* add sync plugins
* iCloud flavor + sync plugin: in-app billing
* iCloud flavor: login credentials fragment + font
* iCloud flavor: new strings
* use account type from string assets instead of hardcoded constant
2016-07-29 14:27:05 +02:00
Ricki Hirner
709f299aa8 Allow large transactions
* version bump to 1.2.1-ose
* upgrade to okhttp 3.4.1
* ical4android/vcard4android: split oversized transactions
2016-07-27 18:24:30 +02:00
Ricki Hirner
0b2abd50c7 Minor changes
* MTM: use multi-process activity
* change library repos to private ones
* upgrade Android gradle plugin
2016-07-14 22:57:00 +02:00
303 changed files with 16725 additions and 12786 deletions

13
.gitmodules vendored
View File

@@ -1,13 +1,12 @@
[submodule "dav4android"]
path = dav4android
url = https://gitlab.com/bitfireAT/dav4android.git
url = ../dav4android.git
[submodule "ical4android"]
path = ical4android
url = https://gitlab.com/bitfireAT/ical4android.git
url = ../ical4android.git
[submodule "vcard4android"]
path = vcard4android
url = https://gitlab.com/bitfireAT/vcard4android.git
[submodule "MemorizingTrustManager"]
path = MemorizingTrustManager
url = https://github.com/ge0rg/MemorizingTrustManager
ignore = dirty
url = ../vcard4android.git
[submodule "cert4android"]
path = cert4android
url = ../cert4android.git

View File

@@ -1,34 +0,0 @@
DAVdroid
========
Please see the [DAVdroid Web site](https://davdroid.bitfire.at) for
comprehensive information about DAVdroid.
DAVdroid is licensed under the [GPLv3 License](LICENSE).
News and updates: [@davdroidapp](https://twitter.com/davdroidapp)
Help and discussion: [DAVdroid forums](https://davdroid.bitfire.at/forums)
Parts of DAVdroid have been outsourced into these libraries:
* [dav4android](https://gitlab.com/bitfireAT/dav4android) WebDAV/CalDav/CardDAV framework
* [ical4android](https://gitlab.com/bitfireAT/ical4android) iCalendar processing and Calendar Provider access
* [vcard4android](https://gitlab.com/bitfireAT/vcard4android) VCard processing and Contacts Provider access
[![Flattr this!](https://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/submit/auto?user_id=bitfire&url=https://davdroid.bitfire.at&title=DAVdroid&category=software)
USED THIRD-PARTY LIBRARIES
==========================
Those libraries are used by DAVdroid (alphabetically):
* [dnsjava](http://www.xbill.org/dnsjava/) [BSD License](http://www.xbill.org/dnsjava/dnsjava-current/LICENSE)
* [ez-vcard](https://code.google.com/p/ez-vcard/) [New BSD License](http://opensource.org/licenses/BSD-3-Clause)
* [iCal4j](http://ical4j.sourceforge.net/) [New BSD License](http://sourceforge.net/p/ical4j/ical4j/ci/default/tree/LICENSE)
* [MemorizingTrustManager](https://github.com/ge0rg/MemorizingTrustManager) [MIT License](https://raw.githubusercontent.com/ge0rg/MemorizingTrustManager/master/LICENSE.txt)
* [okhttp](https://square.github.io/okhttp/) [Apache License, Version 2.0](https://square.github.io/okhttp/#license)
* [Project Lombok](http://projectlombok.org/) [MIT License](http://opensource.org/licenses/mit-license.php)
* [SLF4J](http://www.slf4j.org/) [MIT License](http://www.slf4j.org/license.html)

9
app/README Normal file
View File

@@ -0,0 +1,9 @@
flavor directory
gplay main + davdroid + gplay
icloud main + icloud
managed main + managed
soldupe main + soldupe
standard main + davdroid

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013 2016 Ricki Hirner (bitfire web engineering).
* Copyright (c) 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
@@ -7,27 +7,98 @@
*/
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'org.jetbrains.dokka-android'
ext {
baseVersionName = '2.0.4'
}
android {
compileSdkVersion 23
buildToolsVersion "23.0.3"
compileSdkVersion 27
buildToolsVersion '28.0.2'
defaultConfig {
applicationId "at.bitfire.davdroid"
minSdkVersion 14
targetSdkVersion 23
versionCode 109
resValue "string", "packageID", applicationId
versionCode 245
buildConfigField "long", "buildTime", System.currentTimeMillis() + "L"
minSdkVersion 19 // Android 4.4
targetSdkVersion 27 // Android 8.1
buildConfigField "boolean", "customCerts", "false"
buildConfigField "boolean", "customCertsUI", "true"
// when using this, make sure that notification icons are real bitmaps
vectorDrawables.useSupportLibrary = true
}
flavorDimensions "type"
productFlavors {
standard {
versionName "1.2"
dimension "type"
versionName baseVersionName
buildConfigField "boolean", "customCerts", "true"
}
managed {
dimension "type"
versionName "$baseVersionName-mgd"
applicationId "com.davdroid.managed"
resValue "string", "packageID", applicationId
buildConfigField "boolean", "customCerts", "true"
buildConfigField "boolean", "customCertsUI", "false"
minSdkVersion 21
}
gplay {
versionName "1.2-gplay"
dimension "type"
versionName "$baseVersionName-gplay"
buildConfigField "boolean", "customCerts", "true"
}
icloud {
dimension "type"
versionName "$baseVersionName-icloud"
applicationId "at.bitfire.cloudsync"
resValue "string", "packageID", applicationId
}
soldupe {
dimension "type"
versionName "$baseVersionName-soldupe"
applicationId "com.soldupe.cloudsync"
resValue "string", "packageID", applicationId
minSdkVersion 21
}
}
sourceSets {
standard.java.srcDirs = [ "src/davdroid/java" ]
standard.res.srcDirs = [ "src/davdroid/res" ]
gplay.java.srcDirs = [ "src/gplay/java", "src/davdroid/java" ]
gplay.res.srcDirs = [ "src/gplay/res", "src/davdroid/res" ]
androidTest.java.srcDirs = [ "src/androidTest/java", "src/espressoTest/java" ]
}
signingConfigs {
bitfire {
storeFile file("${System.env.HOME}/Entwicklung/GooglePlay/bitfire.jks")
storePassword '***REMOVED***'
keyAlias 'bitfire'
keyPassword '***REMOVED***'
}
soldupe {
storeFile file("${System.env.HOME}/Entwicklung/GooglePlay/soldupe.jks")
storePassword 'hei8eePh'
keyAlias 'soldupe'
keyPassword 'ocaip6oZ'
}
}
@@ -38,51 +109,59 @@ android {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
signingConfig signingConfigs.bitfire
productFlavors.soldupe.signingConfig signingConfigs.soldupe
}
}
lintOptions {
disable 'GoogleAppIndexingWarning' // we don't need Google indexing, thanks
disable 'GradleDependency'
disable 'GradleDynamicVersion'
disable 'IconColors'
disable 'IconLauncherShape'
disable 'IconMissingDensityFolder'
disable 'ImpliedQuantity'
disable 'MissingTranslation'
disable 'MissingQuantity'
disable 'Recycle' // doesn't understand Lombok's @Cleanup
disable 'ImpliedQuantity', 'MissingQuantity' // quantities from Transifex may vary
disable 'MissingTranslation', 'ExtraTranslation' // translations from Transifex are not always up to date
disable "OnClick" // doesn't recognize Kotlin onClick methods
disable 'RtlEnabled'
disable 'RtlHardcoded'
disable 'Typos'
}
packagingOptions {
exclude 'LICENSE'
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/NOTICE.txt'
exclude 'META-INF/DEPENDENCIES'
exclude 'META-INF/LICENSE'
}
defaultConfig {
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
}
dependencies {
compile project(':dav4android')
compile project(':ical4android')
compile project(':vcard4android')
implementation project(':cert4android')
implementation project(':dav4android')
implementation project(':ical4android')
implementation project(':vcard4android')
compile 'com.android.support:appcompat-v7:23.+'
compile 'com.android.support:cardview-v7:23.+'
compile 'com.android.support:design:23.+'
compile 'com.android.support:preference-v14:23.+'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
compile 'com.github.yukuku:ambilwarna:2.0.1'
compile project(':MemorizingTrustManager')
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support:cardview-v7:27.1.1'
implementation 'com.android.support:design:27.1.1'
implementation 'com.android.support:preference-v14:27.1.1'
compile 'dnsjava:dnsjava:2.1.7'
compile 'org.apache.commons:commons-lang3:3.4'
compile 'org.apache.commons:commons-collections4:4.1'
provided 'org.projectlombok:lombok:1.16.8'
implementation 'com.github.yukuku:ambilwarna:2.0.1'
implementation 'com.mikepenz:aboutlibraries:6.0.9'
implementation 'com.squareup.okhttp3:logging-interceptor:3.11.0'
implementation 'commons-io:commons-io:2.6'
implementation 'dnsjava:dnsjava:2.1.8'
implementation 'org.apache.commons:commons-lang3:3.7'
implementation 'org.apache.commons:commons-collections4:4.1'
// for tests
testCompile 'junit:junit:4.12'
testCompile 'com.squareup.okhttp3:mockwebserver:3.3.1'
androidTestCompile 'com.squareup.okhttp3:mockwebserver:3.3.1'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test:rules:1.0.2'
androidTestImplementation 'junit:junit:4.12'
androidTestImplementation 'com.squareup.okhttp3:mockwebserver:3.11.0'
testImplementation 'junit:junit:4.12'
testImplementation 'com.squareup.okhttp3:mockwebserver:3.11.0'
}

View File

@@ -1,9 +1,9 @@
# ProGuard usage for DAVdroid:
# shrinking yes (main reason for using ProGuard)
# optimization yes
# obfuscation no (DAVdroid is open-source)
# preverification no
# shrinking yes (main reason for using ProGuard)
# optimization yes
# obfuscation no (DAVdroid is open-source)
# preverification no
-dontobfuscate
@@ -12,30 +12,33 @@
-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)
-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
-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 groovy.** # Groovy-based ContentBuilder not used
-dontwarn javax.cache.** # no JCache support in Android
-dontwarn net.fortuna.ical4j.model.**
-dontwarn org.codehaus.groovy.**
-dontwarn org.apache.commons.logging.** # Commons logging is not available
-dontwarn net.fortuna.ical4j.model.** # ignore warnings from Groovy dependency
-keep class net.fortuna.ical4j.model.** { *; } # keep all model classes (properties/factories, created at runtime)
-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 java.nio.file.** # not available on Android
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
# MemorizingTrustManager
-dontwarn de.duenndns.ssl.MemorizingTrustManager
-dontwarn okio.**
-dontwarn javax.annotation.Nullable
-dontwarn javax.annotation.ParametersAreNonnullByDefault
-dontwarn org.conscrypt.**
# dnsjava
-dontwarn sun.net.spi.nameservice.** # not available on Android
-dontwarn sun.net.spi.nameservice.** # not available on Android
# DAVdroid + libs
-keep class at.bitfire.** { *; } # all DAVdroid code is required
-keep class at.bitfire.** { *; } # all DAVdroid code is required

1
app/src/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
espressoTest

View File

@@ -0,0 +1,128 @@
/*
* 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.support.test.InstrumentationRegistry.getInstrumentation
import at.bitfire.cert4android.CustomCertManager
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.mockwebserver.MockWebServer
import org.apache.commons.io.IOUtils
import org.apache.commons.lang3.ArrayUtils.contains
import org.junit.After
import org.junit.Assert.*
import org.junit.Before
import org.junit.Test
import java.net.Socket
import java.security.KeyFactory
import java.security.KeyStore
import java.security.Principal
import java.security.cert.CertificateFactory
import java.security.cert.X509Certificate
import java.security.spec.PKCS8EncodedKeySpec
import javax.net.ssl.SSLSocket
import javax.net.ssl.TrustManagerFactory
import javax.net.ssl.X509ExtendedKeyManager
import javax.net.ssl.X509TrustManager
class CustomTlsSocketFactoryTest {
private lateinit var certMgr: CustomCertManager
private lateinit var factory: CustomTlsSocketFactory
private val server = MockWebServer()
@Before
fun startServer() {
certMgr = CustomCertManager(getInstrumentation().context, false, true)
factory = CustomTlsSocketFactory(null, certMgr)
server.start()
}
@After
fun stopServer() {
server.shutdown()
certMgr.close()
}
@Test
fun testSendClientCertificate() {
var public: X509Certificate? = null
javaClass.classLoader.getResourceAsStream("sample.crt").use {
public = CertificateFactory.getInstance("X509").generateCertificate(it) as? X509Certificate
}
assertNotNull(public)
val keyFactory = KeyFactory.getInstance("RSA")
val private = keyFactory.generatePrivate(PKCS8EncodedKeySpec(readResource("sample.key")))
assertNotNull(private)
val keyStore = KeyStore.getInstance("AndroidKeyStore")
keyStore.load(null)
val alias = "sample"
keyStore.setKeyEntry(alias, private, null, arrayOf(public))
assertTrue(keyStore.containsAlias(alias))
val trustManagerFactory = TrustManagerFactory.getInstance("X509")
trustManagerFactory.init(null as KeyStore?)
val trustManager = trustManagerFactory.trustManagers.first() as X509TrustManager
val factory = CustomTlsSocketFactory(object: X509ExtendedKeyManager() {
override fun getServerAliases(p0: String?, p1: Array<out Principal>?): Array<String>? = null
override fun chooseServerAlias(p0: String?, p1: Array<out Principal>?, p2: Socket?) = null
override fun getClientAliases(p0: String?, p1: Array<out Principal>?) =
arrayOf(alias)
override fun chooseClientAlias(p0: Array<out String>?, p1: Array<out Principal>?, p2: Socket?) =
alias
override fun getCertificateChain(forAlias: String?) =
arrayOf(public).takeIf { forAlias == alias }
override fun getPrivateKey(forAlias: String?) =
private.takeIf { forAlias == alias }
}, trustManager)
/* known client cert test URLs (thanks!):
* - https://prod.idrix.eu/secure/
* - https://server.cryptomix.com/secure/
*/
val client = OkHttpClient.Builder()
.sslSocketFactory(factory, trustManager)
.build()
client.newCall(Request.Builder()
.get()
.url("https://prod.idrix.eu/secure/")
.build()).execute().use { response ->
assertTrue(response.isSuccessful)
assertTrue(response.body()!!.string().contains("CN=User Cert,O=Internet Widgits Pty Ltd,ST=Some-State,C=CA"))
}
}
@Test
fun testUpgradeTLS() {
val s = factory.createSocket(server.hostName, server.port)
assertTrue(s is SSLSocket)
val ssl = s as SSLSocket
assertFalse(contains(ssl.enabledProtocols, "SSLv3"))
assertTrue(contains(ssl.enabledProtocols, "TLSv1"))
assertTrue(contains(ssl.enabledProtocols, "TLSv1.1"))
assertTrue(contains(ssl.enabledProtocols, "TLSv1.2"))
}
private fun readResource(name: String): ByteArray {
this.javaClass.classLoader.getResourceAsStream(name).use {
return IOUtils.toByteArray(it)
}
}
}

View File

@@ -1,53 +0,0 @@
/*
* Copyright © 2013 2015 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.os.Build;
import android.test.InstrumentationTestCase;
import java.io.IOException;
import java.net.Socket;
import javax.net.ssl.SSLSocket;
import de.duenndns.ssl.MemorizingTrustManager;
import okhttp3.mockwebserver.MockWebServer;
public class SSLSocketFactoryCompatTest extends InstrumentationTestCase {
SSLSocketFactoryCompat factory;
MockWebServer server = new MockWebServer();
@Override
protected void setUp() throws Exception {
factory = new SSLSocketFactoryCompat(new MemorizingTrustManager(getInstrumentation().getTargetContext().getApplicationContext()));
server.start();
}
@Override
protected void tearDown() throws Exception {
server.shutdown();
}
public void testUpgradeTLS() throws IOException {
Socket s = factory.createSocket(server.getHostName(), server.getPort());
assertTrue(s instanceof SSLSocket);
SSLSocket ssl = (SSLSocket)s;
assertFalse(org.apache.commons.lang3.ArrayUtils.contains(ssl.getEnabledProtocols(), "SSLv3"));
assertTrue(org.apache.commons.lang3.ArrayUtils.contains(ssl.getEnabledProtocols(), "TLSv1"));
if (Build.VERSION.SDK_INT >= 16) {
assertTrue(org.apache.commons.lang3.ArrayUtils.contains(ssl.getEnabledProtocols(), "TLSv1.1"));
assertTrue(org.apache.commons.lang3.ArrayUtils.contains(ssl.getEnabledProtocols(), "TLSv1.2"));
}
}
}

View File

@@ -1,110 +0,0 @@
/*
* Copyright © 2013 2016 Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
*/
package at.bitfire.davdroid.model;
import android.content.ContentValues;
import junit.framework.TestCase;
import java.io.IOException;
import at.bitfire.dav4android.DavResource;
import at.bitfire.dav4android.exception.DavException;
import at.bitfire.dav4android.exception.HttpException;
import at.bitfire.dav4android.property.ResourceType;
import at.bitfire.davdroid.HttpClient;
import at.bitfire.davdroid.model.ServiceDB.Collections;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
public class CollectionInfoTest extends TestCase {
MockWebServer server = new MockWebServer();
public void testFromDavResource() throws IOException, HttpException, DavException {
// r/w address book
server.enqueue(new MockResponse()
.setResponseCode(207)
.setBody("<multistatus xmlns='DAV:' xmlns:CARD='urn:ietf:params:xml:ns:carddav'>" +
"<response>" +
" <href>/</href>" +
" <propstat><prop>" +
" <resourcetype><collection/><CARD:addressbook/></resourcetype>" +
" <displayname>My Contacts</displayname>" +
" <CARD:addressbook-description>My Contacts Description</CARD:addressbook-description>" +
" </prop></propstat>" +
"</response>" +
"</multistatus>"));
DavResource dav = new DavResource(HttpClient.create(), server.url("/"));
dav.propfind(0, ResourceType.NAME);
CollectionInfo info = CollectionInfo.fromDavResource(dav);
assertEquals(CollectionInfo.Type.ADDRESS_BOOK, info.type);
assertFalse(info.readOnly);
assertEquals("My Contacts", info.displayName);
assertEquals("My Contacts Description", info.description);
// read-only calendar, no display name
server.enqueue(new MockResponse()
.setResponseCode(207)
.setBody("<multistatus xmlns='DAV:' xmlns:CAL='urn:ietf:params:xml:ns:caldav' xmlns:ICAL='http://apple.com/ns/ical/'>" +
"<response>" +
" <href>/</href>" +
" <propstat><prop>" +
" <resourcetype><collection/><CAL:calendar/></resourcetype>" +
" <current-user-privilege-set><privilege><read/></privilege></current-user-privilege-set>" +
" <CAL:calendar-description>My Calendar</CAL:calendar-description>" +
" <CAL:calendar-timezone>tzdata</CAL:calendar-timezone>" +
" <ICAL:calendar-color>#ff0000</ICAL:calendar-color>" +
" </prop></propstat>" +
"</response>" +
"</multistatus>"));
dav = new DavResource(HttpClient.create(), server.url("/"));
dav.propfind(0, ResourceType.NAME);
info = CollectionInfo.fromDavResource(dav);
assertEquals(CollectionInfo.Type.CALENDAR, info.type);
assertTrue(info.readOnly);
assertNull(info.displayName);
assertEquals("My Calendar", info.description);
assertEquals(0xFFFF0000, (int)info.color);
assertEquals("tzdata", info.timeZone);
assertTrue(info.supportsVEVENT);
assertTrue(info.supportsVTODO);
}
public void testFromDB() {
ContentValues values = new ContentValues();
values.put(Collections.ID, 1);
values.put(Collections.SERVICE_ID, 1);
values.put(Collections.URL, "http://example.com");
values.put(Collections.READ_ONLY, 1);
values.put(Collections.DISPLAY_NAME, "display name");
values.put(Collections.DESCRIPTION, "description");
values.put(Collections.COLOR, 0xFFFF0000);
values.put(Collections.TIME_ZONE, "tzdata");
values.put(Collections.SUPPORTS_VEVENT, 1);
values.put(Collections.SUPPORTS_VTODO, 1);
values.put(Collections.SYNC, 1);
CollectionInfo info = CollectionInfo.fromDB(values);
assertEquals(1, info.id);
assertEquals(1, (long)info.serviceID);
assertEquals("http://example.com", info.url);
assertTrue(info.readOnly);
assertEquals("display name", info.displayName);
assertEquals("description", info.description);
assertEquals(0xFFFF0000, (int)info.color);
assertEquals("tzdata", info.timeZone);
assertTrue(info.supportsVEVENT);
assertTrue(info.supportsVTODO);
assertTrue(info.selected);
}
}

View File

@@ -0,0 +1,134 @@
/*
* 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.model
import android.content.ContentValues
import android.support.test.filters.SmallTest
import at.bitfire.dav4android.DavResource
import at.bitfire.dav4android.property.ResourceType
import at.bitfire.davdroid.HttpClient
import at.bitfire.davdroid.model.ServiceDB.Collections
import okhttp3.HttpUrl
import okhttp3.mockwebserver.MockResponse
import okhttp3.mockwebserver.MockWebServer
import org.junit.After
import org.junit.Assert.*
import org.junit.Before
import org.junit.Test
class CollectionInfoTest {
private lateinit var httpClient: HttpClient
private val server = MockWebServer()
@Before
fun setUp() {
httpClient = HttpClient.Builder().build()
}
@After
fun shutDown() {
httpClient.close()
}
@Test
@SmallTest
fun testFromDavResource() {
// r/w address book
server.enqueue(MockResponse()
.setResponseCode(207)
.setBody("<multistatus xmlns='DAV:' xmlns:CARD='urn:ietf:params:xml:ns:carddav'>" +
"<response>" +
" <href>/</href>" +
" <propstat><prop>" +
" <resourcetype><collection/><CARD:addressbook/></resourcetype>" +
" <displayname>My Contacts</displayname>" +
" <CARD:addressbook-description>My Contacts Description</CARD:addressbook-description>" +
" </prop></propstat>" +
"</response>" +
"</multistatus>"))
var info: CollectionInfo? = null
DavResource(httpClient.okHttpClient, server.url("/"))
.propfind(0, ResourceType.NAME) { response, _ ->
info = CollectionInfo(response)
}
assertEquals(CollectionInfo.Type.ADDRESS_BOOK, info?.type)
assertTrue(info!!.privWriteContent)
assertTrue(info!!.privUnbind)
assertEquals("My Contacts", info?.displayName)
assertEquals("My Contacts Description", info?.description)
// read-only calendar, no display name
server.enqueue(MockResponse()
.setResponseCode(207)
.setBody("<multistatus xmlns='DAV:' xmlns:CAL='urn:ietf:params:xml:ns:caldav' xmlns:ICAL='http://apple.com/ns/ical/'>" +
"<response>" +
" <href>/</href>" +
" <propstat><prop>" +
" <resourcetype><collection/><CAL:calendar/></resourcetype>" +
" <current-user-privilege-set><privilege><read/></privilege></current-user-privilege-set>" +
" <CAL:calendar-description>My Calendar</CAL:calendar-description>" +
" <CAL:calendar-timezone>tzdata</CAL:calendar-timezone>" +
" <ICAL:calendar-color>#ff0000</ICAL:calendar-color>" +
" </prop></propstat>" +
"</response>" +
"</multistatus>"))
info = null
DavResource(httpClient.okHttpClient, server.url("/"))
.propfind(0, ResourceType.NAME) { response, _ ->
info = CollectionInfo(response)
}
assertEquals(CollectionInfo.Type.CALENDAR, info?.type)
assertFalse(info!!.privWriteContent)
assertFalse(info!!.privUnbind)
assertNull(info?.displayName)
assertEquals("My Calendar", info?.description)
assertEquals(0xFFFF0000.toInt(), info?.color)
assertEquals("tzdata", info?.timeZone)
assertTrue(info!!.supportsVEVENT)
assertTrue(info!!.supportsVTODO)
}
@Test
fun testFromDB() {
val values = ContentValues()
values.put(Collections.ID, 1)
values.put(Collections.SERVICE_ID, 1)
values.put(Collections.TYPE, CollectionInfo.Type.CALENDAR.name)
values.put(Collections.URL, "http://example.com")
values.put(Collections.PRIV_WRITE_CONTENT, 0)
values.put(Collections.PRIV_UNBIND, 0)
values.put(Collections.DISPLAY_NAME, "display name")
values.put(Collections.DESCRIPTION, "description")
values.put(Collections.COLOR, 0xFFFF0000)
values.put(Collections.TIME_ZONE, "tzdata")
values.put(Collections.SUPPORTS_VEVENT, 1)
values.put(Collections.SUPPORTS_VTODO, 1)
values.put(Collections.SYNC, 1)
val info = CollectionInfo(values)
assertEquals(CollectionInfo.Type.CALENDAR, info.type)
assertEquals(1.toLong(), info.id)
assertEquals(1.toLong(), info.serviceID)
assertEquals(HttpUrl.parse("http://example.com/"), info.url)
assertFalse(info.privWriteContent)
assertFalse(info.privUnbind)
assertEquals("display name", info.displayName)
assertEquals("description", info.description)
assertEquals(0xFFFF0000.toInt(), info.color)
assertEquals("tzdata", info.timeZone)
assertTrue(info.supportsVEVENT)
assertTrue(info.supportsVTODO)
assertTrue(info.selected)
}
}

View File

@@ -0,0 +1,39 @@
/*
* 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.settings
import at.bitfire.davdroid.App
import junit.framework.Assert.assertEquals
import junit.framework.Assert.assertFalse
import org.junit.Test
class DefaultsProviderTest {
private val provider: Provider = DefaultsProvider()
@Test
fun testHas() {
assertEquals(Pair(false, true), provider.has("notExisting"))
assertEquals(Pair(true, true), provider.has(App.OVERRIDE_PROXY))
}
@Test
fun testGet() {
assertEquals(Pair("localhost", true), provider.getString(App.OVERRIDE_PROXY_HOST))
assertEquals(Pair(8118, true), provider.getInt(App.OVERRIDE_PROXY_PORT))
}
@Test
fun testPutRemove() {
assertEquals(Pair(false, true), provider.isWritable(App.OVERRIDE_PROXY))
assertFalse(provider.putBoolean(App.OVERRIDE_PROXY, true))
assertFalse(provider.remove(App.OVERRIDE_PROXY))
}
}

View File

@@ -0,0 +1,44 @@
/*
* 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.settings
import android.support.test.InstrumentationRegistry
import android.support.test.InstrumentationRegistry.getTargetContext
import at.bitfire.davdroid.App
import junit.framework.Assert.assertFalse
import junit.framework.Assert.assertTrue
import org.junit.After
import org.junit.Before
import org.junit.Test
class SettingsTest {
lateinit var settings: Settings.Stub
@Before
fun init() {
InstrumentationRegistry.getContext().isRestricted
settings = Settings.getInstance(getTargetContext())!!
}
@After
fun shutdown() {
settings.close()
}
@Test
fun testHas() {
assertFalse(settings.has("notExisting"))
// provided by DefaultsProvider
assertTrue(settings.has(App.OVERRIDE_PROXY))
}
}

View File

@@ -1,189 +0,0 @@
/*
* Copyright © 2013 2016 Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
*/
package at.bitfire.davdroid.ui.setup;
import android.test.InstrumentationTestCase;
import java.io.IOException;
import java.net.URI;
import at.bitfire.dav4android.DavResource;
import at.bitfire.dav4android.exception.DavException;
import at.bitfire.dav4android.exception.HttpException;
import at.bitfire.dav4android.property.AddressbookHomeSet;
import at.bitfire.dav4android.property.ResourceType;
import at.bitfire.davdroid.App;
import at.bitfire.davdroid.HttpClient;
import at.bitfire.davdroid.ui.setup.DavResourceFinder;
import at.bitfire.davdroid.ui.setup.DavResourceFinder.Configuration.ServiceInfo;
import at.bitfire.davdroid.ui.setup.LoginCredentials;
import okhttp3.OkHttpClient;
import okhttp3.mockwebserver.Dispatcher;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import okhttp3.mockwebserver.RecordedRequest;
public class DavResourceFinderTest extends InstrumentationTestCase {
MockWebServer server = new MockWebServer();
DavResourceFinder finder;
OkHttpClient client;
LoginCredentials credentials;
private static final String
PATH_NO_DAV = "/nodav",
PATH_CALDAV = "/caldav",
PATH_CARDDAV = "/carddav",
PATH_CALDAV_AND_CARDDAV = "/both-caldav-carddav",
SUBPATH_PRINCIPAL = "/principal",
SUBPATH_ADDRESSBOOK_HOMESET = "/addressbooks",
SUBPATH_ADDRESSBOOK = "/addressbooks/private-contacts";
@Override
protected void setUp() throws Exception {
server.setDispatcher(new TestDispatcher());
server.start();
credentials = new LoginCredentials(URI.create("/"), "mock", "12345", true);
finder = new DavResourceFinder(getInstrumentation().getContext(), credentials);
client = HttpClient.create();
client = HttpClient.addAuthentication(client, credentials.userName, credentials.password, credentials.authPreemptive);
}
@Override
protected void tearDown() throws Exception {
server.shutdown();
}
public void testRememberIfAddressBookOrHomeset() throws IOException, HttpException, DavException {
ServiceInfo info;
// before dav.propfind(), no info is available
DavResource dav = new DavResource(client, server.url(PATH_CARDDAV + SUBPATH_PRINCIPAL));
finder.rememberIfAddressBookOrHomeset(dav, info = new ServiceInfo());
assertEquals(0, info.collections.size());
assertEquals(0, info.homeSets.size());
// recognize home set
dav.propfind(0, AddressbookHomeSet.NAME);
finder.rememberIfAddressBookOrHomeset(dav, info = new ServiceInfo());
assertEquals(0, info.collections.size());
assertEquals(1, info.homeSets.size());
assertEquals(server.url(PATH_CARDDAV + SUBPATH_ADDRESSBOOK_HOMESET + "/").uri(), info.homeSets.iterator().next());
// recognize address book
dav = new DavResource(client, server.url(PATH_CARDDAV + SUBPATH_ADDRESSBOOK));
dav.propfind(0, ResourceType.NAME);
finder.rememberIfAddressBookOrHomeset(dav, info = new ServiceInfo());
assertEquals(1, info.collections.size());
assertEquals(server.url(PATH_CARDDAV + SUBPATH_ADDRESSBOOK + "/").uri(), info.collections.keySet().iterator().next());
assertEquals(0, info.homeSets.size());
}
public void testProvidesService() throws IOException {
assertFalse(finder.providesService(server.url(PATH_NO_DAV), DavResourceFinder.Service.CALDAV));
assertFalse(finder.providesService(server.url(PATH_NO_DAV), DavResourceFinder.Service.CARDDAV));
assertTrue(finder.providesService(server.url(PATH_CALDAV), DavResourceFinder.Service.CALDAV));
assertFalse(finder.providesService(server.url(PATH_CALDAV), DavResourceFinder.Service.CARDDAV));
assertTrue(finder.providesService(server.url(PATH_CARDDAV), DavResourceFinder.Service.CARDDAV));
assertFalse(finder.providesService(server.url(PATH_CARDDAV), DavResourceFinder.Service.CALDAV));
assertTrue(finder.providesService(server.url(PATH_CALDAV_AND_CARDDAV), DavResourceFinder.Service.CALDAV));
assertTrue(finder.providesService(server.url(PATH_CALDAV_AND_CARDDAV), DavResourceFinder.Service.CARDDAV));
}
public void testGetCurrentUserPrincipal() throws IOException, HttpException, DavException {
assertNull(finder.getCurrentUserPrincipal(server.url(PATH_NO_DAV), DavResourceFinder.Service.CALDAV));
assertNull(finder.getCurrentUserPrincipal(server.url(PATH_NO_DAV), DavResourceFinder.Service.CARDDAV));
assertEquals(
server.url(PATH_CALDAV + SUBPATH_PRINCIPAL).uri(),
finder.getCurrentUserPrincipal(server.url(PATH_CALDAV), DavResourceFinder.Service.CALDAV)
);
assertNull(finder.getCurrentUserPrincipal(server.url(PATH_CALDAV), DavResourceFinder.Service.CARDDAV));
assertEquals(
server.url(PATH_CARDDAV + SUBPATH_PRINCIPAL).uri(),
finder.getCurrentUserPrincipal(server.url(PATH_CARDDAV), DavResourceFinder.Service.CARDDAV)
);
assertNull(finder.getCurrentUserPrincipal(server.url(PATH_CARDDAV), DavResourceFinder.Service.CALDAV));
}
// mock server
public class TestDispatcher extends Dispatcher {
@Override
public MockResponse dispatch(RecordedRequest rq) throws InterruptedException {
if (!checkAuth(rq))
return new MockResponse().setResponseCode(401);
String path = rq.getPath();
if ("OPTIONS".equalsIgnoreCase(rq.getMethod())) {
String dav = null;
if (path.startsWith(PATH_CALDAV))
dav = "calendar-access";
else if (path.startsWith(PATH_CARDDAV))
dav = "addressbook";
else if (path.startsWith(PATH_CALDAV_AND_CARDDAV))
dav = "calendar-access, addressbook";
MockResponse response = new MockResponse().setResponseCode(200);
if (dav != null)
response.addHeader("DAV", dav);
return response;
} else if ("PROPFIND".equalsIgnoreCase(rq.getMethod())) {
String props = null;
switch (path) {
case PATH_CALDAV:
case PATH_CARDDAV:
props = "<current-user-principal><href>" + path + SUBPATH_PRINCIPAL + "</href></current-user-principal>";
break;
case PATH_CARDDAV + SUBPATH_PRINCIPAL:
props = "<CARD:addressbook-home-set>" +
" <href>" + PATH_CARDDAV + SUBPATH_ADDRESSBOOK_HOMESET + "</href>" +
"</CARD:addressbook-home-set>";
break;
case PATH_CARDDAV + SUBPATH_ADDRESSBOOK:
props = "<resourcetype>" +
" <collection/>" +
" <CARD:addressbook/>" +
"</resourcetype>";
break;
}
App.log.info("Sending props: " + props);
return new MockResponse()
.setResponseCode(207)
.setBody("<multistatus xmlns='DAV:' xmlns:CARD='urn:ietf:params:xml:ns:carddav'>" +
"<response>" +
" <href>" + rq.getPath() + "</href>" +
" <propstat><prop>" + props + "</prop></propstat>" +
"</response>" +
"</multistatus>");
}
return new MockResponse().setResponseCode(404);
}
private boolean checkAuth(RecordedRequest rq) {
return "Basic bW9jazoxMjM0NQ==".equals(rq.getHeader("Authorization"));
}
}
}

View File

@@ -0,0 +1,189 @@
/*
* 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.ui.setup
import android.support.test.InstrumentationRegistry.getTargetContext
import android.support.test.filters.SmallTest
import at.bitfire.dav4android.DavResource
import at.bitfire.dav4android.property.AddressbookHomeSet
import at.bitfire.dav4android.property.ResourceType
import at.bitfire.davdroid.HttpClient
import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.model.Credentials
import at.bitfire.davdroid.ui.setup.DavResourceFinder.Configuration.ServiceInfo
import okhttp3.mockwebserver.Dispatcher
import okhttp3.mockwebserver.MockResponse
import okhttp3.mockwebserver.MockWebServer
import okhttp3.mockwebserver.RecordedRequest
import org.junit.After
import org.junit.Assert.*
import org.junit.Before
import org.junit.Test
import java.net.URI
class DavResourceFinderTest {
companion object {
private const val PATH_NO_DAV = "/nodav"
private const val PATH_CALDAV = "/caldav"
private const val PATH_CARDDAV = "/carddav"
private const val PATH_CALDAV_AND_CARDDAV = "/both-caldav-carddav"
private const val SUBPATH_PRINCIPAL = "/principal"
private const val SUBPATH_ADDRESSBOOK_HOMESET = "/addressbooks"
private const val SUBPATH_ADDRESSBOOK = "/addressbooks/private-contacts"
}
val server = MockWebServer()
lateinit var finder: DavResourceFinder
lateinit var client: HttpClient
lateinit var loginInfo: LoginInfo
@Before
fun initServerAndClient() {
server.setDispatcher(TestDispatcher())
server.start()
loginInfo = LoginInfo(URI.create("/"), Credentials("mock", "12345"))
finder = DavResourceFinder(getTargetContext(), loginInfo)
client = HttpClient.Builder()
.addAuthentication(null, loginInfo.credentials)
.build()
}
@After
fun stopServer() {
server.shutdown()
}
@Test
@SmallTest
fun testRememberIfAddressBookOrHomeset() {
// recognize home set
var info = ServiceInfo()
DavResource(client.okHttpClient, server.url(PATH_CARDDAV + SUBPATH_PRINCIPAL))
.propfind(0, AddressbookHomeSet.NAME) { response, _ ->
finder.scanCardDavResponse(response, info)
}
assertEquals(0, info.collections.size)
assertEquals(1, info.homeSets.size)
assertEquals(server.url("$PATH_CARDDAV$SUBPATH_ADDRESSBOOK_HOMESET/"), info.homeSets.first())
// recognize address book
info = ServiceInfo()
DavResource(client.okHttpClient, server.url(PATH_CARDDAV + SUBPATH_ADDRESSBOOK))
.propfind(0, ResourceType.NAME) { response, _ ->
finder.scanCardDavResponse(response, info)
}
assertEquals(1, info.collections.size)
assertEquals(server.url("$PATH_CARDDAV$SUBPATH_ADDRESSBOOK/"), info.collections.keys.first())
assertEquals(0, info.homeSets.size)
}
@Test
fun testProvidesService() {
assertFalse(finder.providesService(server.url(PATH_NO_DAV), DavResourceFinder.Service.CALDAV))
assertFalse(finder.providesService(server.url(PATH_NO_DAV), DavResourceFinder.Service.CARDDAV))
assertTrue(finder.providesService(server.url(PATH_CALDAV), DavResourceFinder.Service.CALDAV))
assertFalse(finder.providesService(server.url(PATH_CALDAV), DavResourceFinder.Service.CARDDAV))
assertTrue(finder.providesService(server.url(PATH_CARDDAV), DavResourceFinder.Service.CARDDAV))
assertFalse(finder.providesService(server.url(PATH_CARDDAV), DavResourceFinder.Service.CALDAV))
assertTrue(finder.providesService(server.url(PATH_CALDAV_AND_CARDDAV), DavResourceFinder.Service.CALDAV))
assertTrue(finder.providesService(server.url(PATH_CALDAV_AND_CARDDAV), DavResourceFinder.Service.CARDDAV))
}
@Test
fun testGetCurrentUserPrincipal() {
assertNull(finder.getCurrentUserPrincipal(server.url(PATH_NO_DAV), DavResourceFinder.Service.CALDAV))
assertNull(finder.getCurrentUserPrincipal(server.url(PATH_NO_DAV), DavResourceFinder.Service.CARDDAV))
assertEquals(
server.url(PATH_CALDAV + SUBPATH_PRINCIPAL),
finder.getCurrentUserPrincipal(server.url(PATH_CALDAV), DavResourceFinder.Service.CALDAV)
)
assertNull(finder.getCurrentUserPrincipal(server.url(PATH_CALDAV), DavResourceFinder.Service.CARDDAV))
assertEquals(
server.url(PATH_CARDDAV + SUBPATH_PRINCIPAL),
finder.getCurrentUserPrincipal(server.url(PATH_CARDDAV), DavResourceFinder.Service.CARDDAV)
)
assertNull(finder.getCurrentUserPrincipal(server.url(PATH_CARDDAV), DavResourceFinder.Service.CALDAV))
}
// mock server
class TestDispatcher: Dispatcher() {
override fun dispatch(rq: RecordedRequest): MockResponse {
if (!checkAuth(rq)) {
val authenticate = MockResponse().setResponseCode(401)
authenticate.setHeader("WWW-Authenticate", "Basic realm=\"test\"")
return authenticate
}
val path = rq.path
if (rq.method.equals("OPTIONS", true)) {
val dav = when {
path.startsWith(PATH_CALDAV) -> "calendar-access"
path.startsWith(PATH_CARDDAV) -> "addressbook"
path.startsWith(PATH_CALDAV_AND_CARDDAV) -> "calendar-access, addressbook"
else -> null
}
val response = MockResponse().setResponseCode(200)
if (dav != null)
response.addHeader("DAV", dav)
return response
} else if (rq.method.equals("PROPFIND", true)) {
val props: String?
when (path) {
PATH_CALDAV,
PATH_CARDDAV ->
props = "<current-user-principal><href>$path$SUBPATH_PRINCIPAL</href></current-user-principal>"
PATH_CARDDAV + SUBPATH_PRINCIPAL ->
props = "<CARD:addressbook-home-set>" +
" <href>$PATH_CARDDAV$SUBPATH_ADDRESSBOOK_HOMESET</href>" +
"</CARD:addressbook-home-set>"
PATH_CARDDAV + SUBPATH_ADDRESSBOOK ->
props = "<resourcetype>" +
" <collection/>" +
" <CARD:addressbook/>" +
"</resourcetype>"
else -> props = null
}
Logger.log.info("Sending props: $props")
return MockResponse()
.setResponseCode(207)
.setBody("<multistatus xmlns='DAV:' xmlns:CARD='urn:ietf:params:xml:ns:carddav'>" +
"<response>" +
" <href>${rq.path}</href>" +
" <propstat><prop>$props</prop></propstat>" +
"</response>" +
"</multistatus>")
}
return MockResponse().setResponseCode(404)
}
private fun checkAuth(rq: RecordedRequest) =
rq.getHeader("Authorization") == "Basic bW9jazoxMjM0NQ=="
}
}

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -0,0 +1,24 @@
-----BEGIN CERTIFICATE-----
MIIEEzCCAfsCAQEwDQYJKoZIhvcNAQEFBQAwRjELMAkGA1UEBhMCQ0ExEzARBgNV
BAgMClNvbWUtU3RhdGUxEDAOBgNVBAoMB0NBIENlcnQxEDAOBgNVBAMMB0NBIENl
cnQwHhcNMTgwMTEzMjAyOTI5WhcNMTkwMTEzMjAyOTI5WjBZMQswCQYDVQQGEwJD
QTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0
cyBQdHkgTHRkMRIwEAYDVQQDDAlVc2VyIENlcnQwggEiMA0GCSqGSIb3DQEBAQUA
A4IBDwAwggEKAoIBAQDqOyHAeG4psE/f6i/eTfwbhn6j7WaFXxZiSOWwpQZmzRrx
MrfkABJCk0X7KNgCaJcmBkG9G1Ri4HfKrxvJFswMXknlq+0ulGBk7oDnZM+pihuX
3D9VCWMMkCqYhLCGADj2zB2mkX4LpcMRi6XoOetKURE/vcIy7rSLAtJM6ZRdftfh
2ZxnautS1Tyujh9Au3NI/+Of80tT/nA+oBJQeT1fB/ga1OQlZP5kjSaA7IPiIbTz
QBO+r898MvqK/lwsvOYnWAp7TY03z+vPfCs0zjijZEl9Wrl0hW6o5db5kU1v5bcr
p87hxFJsGD2HIr2y6kvYfL2hn+h9iANyYdRnUgapAgMBAAEwDQYJKoZIhvcNAQEF
BQADggIBAHANsiJITedXPyp89lVMEmGY3zKtOqgQ3tqjvjlNt2sdPnj7wmZbmrNd
sa90S/UwOn8PzEFOVxYy1BPlljlEjtjmc4OHMcm4P4Zv36uawHilmK8V+zT59gCK
ftB5FP2TLFUFi2X9o8J06d0xJRE77uewN155NV4RmPuP4b/tMmeixoQppHqLqEr5
lgEUnt3Mh1ctmeFQFJR6lJ01hlB0gdpVHIhzrVLTO3uo8ePLJTmxP6tyKl/HXj9F
mpVsKb1kriKwbkGczfw99OUZeUVbTwQOR07r0SrG71B7IuDvxIORnhQc1OUjt7ob
wjdaZauAHxpGBRu+hw9Yqaxchk9Gldy1nEjGyyVCD0FU5taXbl8PhBWEDc4U9tI+
xVNmPpsSuCsbz3Mjd1YIVRGL99vLrKsQcj+TNM+jJKKRKes3ihl+l/0FwG6UuO7L
EvjlUg5hOtYi1D7xuYyMjroGBGh7swYMt6w4eCDbcjzcCkaCi0H2pScM/rLBpDjS
LIoGCvZ1LBdi933/iOj1/8dxGZwY6fEgcyiD2n0xAgYIniLWjEZXOMdIK5FNTNga
Tswanvp+6Noa4oIu/hl/LXvPMsouaWfSEbRe0Dshi3GpLj3YtEHoN9DHB8bn7jy5
34By81GT41m5kq3hWP//x9kSHYSADpbovCbKbElU1qSt6vTVR4nq
-----END CERTIFICATE-----

View File

Binary file not shown.

View File

@@ -0,0 +1,68 @@
/*
* 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.ui
import android.app.Activity
import android.content.Intent
import android.net.Uri
import android.view.Menu
import android.view.MenuItem
import at.bitfire.davdroid.App
import at.bitfire.davdroid.BuildConfig
import at.bitfire.davdroid.R
import at.bitfire.davdroid.settings.ISettings
class DefaultAccountsDrawerHandler: IAccountsDrawerHandler {
companion object {
private const val BETA_FEEDBACK_URI = "mailto:support@davdroid.com?subject=${BuildConfig.APPLICATION_ID}/${BuildConfig.VERSION_NAME} feedback (${BuildConfig.VERSION_CODE})"
}
override fun onSettingsChanged(settings: ISettings?, menu: Menu) {
if (BuildConfig.VERSION_NAME.contains("-beta") || BuildConfig.VERSION_NAME.contains("-rc"))
menu.findItem(R.id.nav_beta_feedback).isVisible = true
}
override fun onNavigationItemSelected(activity: Activity, item: MenuItem): Boolean {
when (item.itemId) {
R.id.nav_about ->
activity.startActivity(Intent(activity, AboutActivity::class.java))
R.id.nav_app_settings ->
activity.startActivity(Intent(activity, AppSettingsActivity::class.java))
R.id.nav_beta_feedback -> {
val intent = Intent(Intent.ACTION_SENDTO, Uri.parse(BETA_FEEDBACK_URI))
if (activity.packageManager.resolveActivity(intent, 0) != null)
activity.startActivity(intent)
}
R.id.nav_twitter ->
activity.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("https://twitter.com/davdroidapp")))
R.id.nav_website ->
activity.startActivity(Intent(Intent.ACTION_VIEW, App.homepageUrl(activity)))
R.id.nav_manual ->
activity.startActivity(Intent(Intent.ACTION_VIEW, App.homepageUrl(activity)
.buildUpon().appendEncodedPath("manual/").build()))
R.id.nav_faq ->
activity.startActivity(Intent(Intent.ACTION_VIEW, App.homepageUrl(activity)
.buildUpon().appendEncodedPath("faq/").build()))
R.id.nav_forums ->
activity.startActivity(Intent(Intent.ACTION_VIEW, App.homepageUrl(activity)
.buildUpon().appendEncodedPath("forums/").build()))
R.id.nav_donate ->
if (BuildConfig.FLAVOR != App.FLAVOR_GOOGLE_PLAY)
activity.startActivity(Intent(Intent.ACTION_VIEW, App.homepageUrl(activity)
.buildUpon().appendEncodedPath("donate/").build()))
else ->
return false
}
return true
}
}

View File

@@ -0,0 +1,211 @@
/*
* 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.ui.setup
import android.net.Uri
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.security.KeyChain
import android.support.v4.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.CompoundButton
import at.bitfire.dav4android.Constants
import at.bitfire.davdroid.R
import kotlinx.android.synthetic.standard.login_credentials_fragment.view.*
import java.net.IDN
import java.net.URI
import java.net.URISyntaxException
import java.util.logging.Level
class DefaultLoginCredentialsFragment: Fragment(), CompoundButton.OnCheckedChangeListener {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
val v = inflater.inflate(R.layout.login_credentials_fragment, container, false)
if (savedInstanceState == null) {
// first call
activity?.intent?.let {
// we've got initial login data
val url = it.getStringExtra(LoginActivity.EXTRA_URL)
val username = it.getStringExtra(LoginActivity.EXTRA_USERNAME)
val password = it.getStringExtra(LoginActivity.EXTRA_PASSWORD)
if (url != null) {
v.login_type_urlpwd.isChecked = true
v.urlpwd_base_url.setText(url)
v.urlpwd_user_name.setText(username)
v.urlpwd_password.setText(password)
} else {
v.login_type_email.isChecked = true
v.email_address.setText(username)
v.email_password.setText(password)
}
}
}
v.urlcert_select_cert.setOnClickListener {
KeyChain.choosePrivateKeyAlias(activity, { alias ->
Handler(Looper.getMainLooper()).post {
v.urlcert_cert_alias.text = alias
v.urlcert_cert_alias.error = null
}
}, null, null, null, -1, view!!.urlcert_cert_alias.text.toString())
}
v.login.setOnClickListener {
validateLoginData()?.let { info ->
DetectConfigurationFragment.newInstance(info).show(fragmentManager, null)
}
}
// initialize to Login by email
onCheckedChanged(v)
v.login_type_email.setOnCheckedChangeListener(this)
v.login_type_urlpwd.setOnCheckedChangeListener(this)
v.login_type_urlcert.setOnCheckedChangeListener(this)
return v
}
override fun onCheckedChanged(buttonView: CompoundButton, isChecked: Boolean) {
onCheckedChanged(view!!)
}
private fun onCheckedChanged(v: View) {
v.login_type_email_details.visibility = if (v.login_type_email.isChecked) View.VISIBLE else View.GONE
v.login_type_urlpwd_details.visibility = if (v.login_type_urlpwd.isChecked) View.VISIBLE else View.GONE
v.login_type_urlcert_details.visibility = if (v.login_type_urlcert.isChecked) View.VISIBLE else View.GONE
}
private fun validateLoginData(): LoginInfo? {
val view = requireNotNull(view)
when {
// Login with email address
view.login_type_email.isChecked -> {
var uri: URI? = null
var valid = true
val email = view.email_address.text.toString()
if (!email.matches(Regex(".+@.+"))) {
view.email_address.error = getString(R.string.login_email_address_error)
valid = false
} else
try {
uri = URI("mailto", email, null)
} catch (e: URISyntaxException) {
view.email_address.error = e.localizedMessage
valid = false
}
val password = view.email_password.text.toString()
if (password.isEmpty()) {
view.email_password.error = getString(R.string.login_password_required)
valid = false
}
return if (valid && uri != null)
LoginInfo(uri, email, password)
else
null
}
// Login with URL and user name
view.login_type_urlpwd.isChecked -> {
var valid = true
val baseUrl = Uri.parse(view.urlpwd_base_url.text.toString())
val uri = validateBaseUrl(baseUrl, false) { message ->
view.urlpwd_base_url.error = message
valid = false
}
val userName = view.urlpwd_user_name.text.toString()
if (userName.isBlank()) {
view.urlpwd_user_name.error = getString(R.string.login_user_name_required)
valid = false
}
val password = view.urlpwd_password.text.toString()
if (password.isEmpty()) {
view.urlpwd_password.error = getString(R.string.login_password_required)
valid = false
}
return if (valid && uri != null)
LoginInfo(uri, userName, password)
else
null
}
// Login with URL and client certificate
view.login_type_urlcert.isChecked -> {
var valid = true
val baseUrl = Uri.parse(view.urlcert_base_url.text.toString())
val uri = validateBaseUrl(baseUrl, true) { message ->
view.urlcert_base_url.error = message
valid = false
}
val alias = view.urlcert_cert_alias.text.toString()
if (alias.isEmpty()) {
view.urlcert_cert_alias.error = ""
valid = false
}
if (valid && uri != null)
return LoginInfo(uri, certificateAlias = alias)
}
}
return null
}
private fun validateBaseUrl(baseUrl: Uri, httpsRequired: Boolean, reportError: (String) -> Unit): URI? {
var uri: URI? = null
val scheme = baseUrl.scheme
if ((!httpsRequired && scheme.equals("http", true)) || scheme.equals("https", true)) {
var host = baseUrl.host
if (host.isNullOrBlank())
reportError(getString(R.string.login_url_host_name_required))
else
try {
host = IDN.toASCII(host)
} catch (e: IllegalArgumentException) {
Constants.log.log(Level.WARNING, "Host name not conforming to RFC 3490", e)
}
val path = baseUrl.encodedPath
val port = baseUrl.port
try {
uri = URI(baseUrl.scheme, null, host, port, path, null, null)
} catch (e: URISyntaxException) {
reportError(e.localizedMessage)
}
} else
reportError(getString(if (httpsRequired)
R.string.login_url_must_be_https
else
R.string.login_url_must_be_http_or_https))
return uri
}
class Factory: ILoginCredentialsFragment {
override fun getFragment() = DefaultLoginCredentialsFragment()
}
}

View File

@@ -0,0 +1,201 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- We don't want the keyboard up when the user arrives in this initial screen -->
<View android:layout_height="0dp"
android:layout_width="0dp"
android:focusable="true"
android:focusableInTouchMode="true"
android:contentDescription="@null"
android:importantForAccessibility="no" tools:ignore="UnusedAttribute">
<requestFocus/>
</View>
<ScrollView android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_margin="@dimen/activity_margin">
<RadioGroup
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:animateLayoutChanges="true">
<RadioButton
android:id="@+id/login_type_email"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:checked="true"
android:text="@string/login_type_email"
android:paddingLeft="14dp" tools:ignore="RtlSymmetry"
style="@style/login_type_headline"/>
<LinearLayout
android:id="@+id/login_type_email_details"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="8dp"
android:paddingBottom="16dp"
android:orientation="vertical">
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.design.widget.TextInputEditText
android:id="@+id/email_address"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/login_email_address"
android:inputType="textEmailAddress"/>
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:passwordToggleEnabled="true">
<android.support.design.widget.TextInputEditText
android:id="@+id/email_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/login_password"
android:fontFamily="monospace"
android:inputType="textPassword"/>
</android.support.design.widget.TextInputLayout>
</LinearLayout>
<RadioButton
android:id="@+id/login_type_urlpwd"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/login_type_url"
android:layout_marginTop="16dp"
android:paddingLeft="14dp" tools:ignore="RtlSymmetry"
style="@style/login_type_headline"/>
<LinearLayout
android:id="@+id/login_type_urlpwd_details"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="8dp"
android:paddingBottom="16dp"
android:orientation="vertical">
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.design.widget.TextInputEditText
android:id="@+id/urlpwd_base_url"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/login_base_url"
android:inputType="textUri"/>
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.design.widget.TextInputEditText
android:id="@+id/urlpwd_user_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/login_user_name"
android:inputType="textEmailAddress"/>
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:passwordToggleEnabled="true">
<android.support.design.widget.TextInputEditText
android:id="@+id/urlpwd_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="monospace"
android:inputType="textPassword"
android:hint="@string/login_password"/>
</android.support.design.widget.TextInputLayout>
</LinearLayout>
<RadioButton
android:id="@+id/login_type_urlcert"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/login_type_url_certificate"
android:layout_marginTop="16dp"
android:paddingLeft="14dp" tools:ignore="RtlSymmetry"
style="@style/login_type_headline"/>
<LinearLayout
android:id="@+id/login_type_urlcert_details"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="8dp"
android:paddingBottom="16dp"
android:orientation="vertical">
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.design.widget.TextInputEditText
android:id="@+id/urlcert_base_url"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/login_base_url"
android:inputType="textUri"/>
</android.support.design.widget.TextInputLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/urlcert_cert_alias"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:paddingLeft="3dp"
android:paddingRight="3dp"
style="@style/Base.TextAppearance.AppCompat.Body1"
android:textSize="16sp"/>
<Button
android:id="@+id/urlcert_select_cert"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/Widget.AppCompat.Button.Borderless.Colored"
android:text="@string/login_select_certificate"/>
</LinearLayout>
</LinearLayout>
</RadioGroup>
</ScrollView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/stepper_nav_bar">
<Space
android:layout_width="0dp"
android:layout_weight="1"
style="@style/stepper_nav_button"/>
<Button
android:id="@+id/login"
android:layout_width="0dp"
android:layout_weight="1"
android:text="@string/login_login"
style="@style/stepper_nav_button"/>
</LinearLayout>
</LinearLayout>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/primaryColor" />
<foreground android:drawable="@mipmap/ic_launcher_foreground" />
</adaptive-icon>

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

View File

@@ -0,0 +1,113 @@
<?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 Llibreta dAdreces</string>
<string name="address_books_authority_title">Llibreta dadreces</string>
<string name="help">Ajuda</string>
<string name="manage_accounts">Gestiona comptes</string>
<string name="please_wait">Esperi si us plau…</string>
<string name="send">Enviar</string>
<string name="notification_channel_debugging">Depurador</string>
<string name="notification_channel_general">Altres missatges importants</string>
<string name="notification_channel_sync">Sincronització</string>
<string name="notification_channel_sync_io_errors">Xarxa i errors E/S</string>
<string name="notification_channel_sync_status">Estat dels misatges</string>
<!--startup dialogs-->
<string name="startup_battery_optimization_disable">Desactiva per DAVdroid</string>
<string name="startup_dont_show_again">No mostrar de nou</string>
<string name="startup_donate">Informació de Codi Obert</string>
<string name="startup_donate_message">Som feliços de que utilitzis DAVdroid, el qual és programari lliure (GPLv3). Desenvolupar DAVdroid ens porte moltes hores i molta feina, si us plau, considera fer una donació.</string>
<string name="startup_donate_now">Mostra la pàgina de donació</string>
<string name="startup_donate_later">Més tard</string>
<string name="startup_google_play_accounts_removed">Informació d\'errors DRM a Play Store</string>
<string name="startup_more_info">Més informació</string>
<string name="startup_opentasks_not_installed">OpenTasks no està instal·lada</string>
<string name="startup_opentasks_not_installed_install">Instal·lar OpenTasks</string>
<!--AboutActivity-->
<!--global settings-->
<string name="logging_no_external_storage">Emmagatzematge extern no trobat</string>
<!--AccountsActivity-->
<string name="navigation_drawer_about">Quan a / Llicència</string>
<string name="navigation_drawer_beta_feedback">Retroacció de la Beta</string>
<string name="navigation_drawer_settings">Paràmetres</string>
<string name="navigation_drawer_news_updates">Novetats &amp; Actualitzacions</string>
<string name="navigation_drawer_external_links">Enllaços externs</string>
<string name="navigation_drawer_website">Pàgina web</string>
<string name="navigation_drawer_manual">Manual</string>
<string name="navigation_drawer_faq">Preguntes Freqüents</string>
<string name="navigation_drawer_forums">Ajuda / Fòrums</string>
<string name="navigation_drawer_donate">Fer donació</string>
<string name="accounts_global_sync_enable">Activar</string>
<!--DavService-->
<!--AppSettingsActivity-->
<string name="app_settings">Paràmetres</string>
<string name="app_settings_user_interface">Interfície dusuari</string>
<string name="app_settings_reset_hints">Reiniciar pistes</string>
<string name="app_settings_security">Seguretat</string>
<string name="app_settings_debug">Depurador</string>
<!--AccountActivity-->
<string name="account_synchronize_now">Sincronitza ara</string>
<string name="account_synchronizing_now">Sincronitzant ara</string>
<string name="account_settings">Paràmetres del compte</string>
<string name="account_rename">Canvia el nom al compte</string>
<string name="account_rename_rename">Canvia el nom</string>
<string name="account_delete">Esborra el compte</string>
<string name="account_delete_confirmation_title">Segur que vols esborrar el compte?</string>
<string name="account_carddav">CardDAV</string>
<string name="account_caldav">CalDAV</string>
<string name="account_webcal">Webcal</string>
<string name="account_synchronize_this_collection">Sincronitzar aquesta col·lecció</string>
<string name="account_read_only">Només de lectura</string>
<string name="account_calendar">Calendari</string>
<string name="account_task_list">Llista de tasques</string>
<string name="account_refresh_address_book_list">Actualitza la llista de llibretes dadreces</string>
<string name="account_create_new_address_book">Crear nova llibreta dadreces</string>
<string name="account_refresh_calendar_list">Actualitzar llista de calendaris</string>
<string name="account_create_new_calendar">Crear nou calendari</string>
<string name="account_install_icsdroid">Instal·lar ICSdroid</string>
<!--AddAccountActivity-->
<string name="login_title">Afegir compte</string>
<string name="login_type_email">Entra amb una adreça de correu electrònic</string>
<string name="login_email_address">Correu electrònic</string>
<string name="login_email_address_error">Es requereix un correu electrònic vàlid</string>
<string name="login_password">Contrasenya</string>
<string name="login_password_required">Es requereix contrasenya</string>
<string name="login_type_url">Entra amb una URL i un nom d\'usuari</string>
<string name="login_url_must_be_http_or_https">La URL hauria de començar amb http(s)://</string>
<string name="login_url_must_be_https">La URL hauria de començar amb https://</string>
<string name="login_url_host_name_required">Es requereix nom d\'amfitrió</string>
<string name="login_user_name">Nom d\'usuari/a</string>
<string name="login_user_name_required">Es requereix nom d\'usuari/a</string>
<string name="login_base_url">URL base</string>
<string name="login_select_certificate">Selecciona certificat</string>
<string name="login_login">Entrada</string>
<string name="login_back">Sortir</string>
<string name="login_create_account">Crear compte</string>
<string name="login_account_name">Nom del compte</string>
<!--AccountSettingsActivity-->
<string name="settings_title">Paràmetres: %s</string>
<string name="settings_authentication">Autentificació</string>
<string name="settings_username">Nom d\'usuari/a</string>
<string name="settings_enter_username">Escriu el nom d\'usuari/a:</string>
<string name="settings_password">Contrasenya</string>
<string name="settings_enter_password">Escriu la teva contrasenya</string>
<string name="settings_sync">Sincronització</string>
<string name="settings_sync_summary_manually">Només a mà</string>
<string-array name="settings_sync_interval_names">
<item>Només a mà</item>
<item>Cada 15 minuts</item>
<item>Cada 30 minuts</item>
<item>Cada hora</item>
<item>Cada 2 hores</item>
<item>Cada 4 hores</item>
<item>Una vegada al dia</item>
</string-array>
<string name="settings_sync_wifi_only">Sincronitzar només amb WI-FI</string>
<string name="settings_carddav">CardDAV</string>
<string name="settings_caldav">CalDAV</string>
<!--collection management-->
<!--ExceptionInfoFragment-->
<!--sync adapters and DebugInfoActivity-->
<!--cert4android-->
</resources>

View File

@@ -4,31 +4,25 @@
<string name="app_name">DAVdroid</string>
<string name="help">Pomoc</string>
<string name="manage_accounts">Spravovat účty</string>
<string name="please_wait">Chvíli strpení ...</string>
<string name="please_wait">Chvíli strpení </string>
<string name="send">Odeslat</string>
<!--startup dialogs-->
<string name="startup_battery_optimization_disable">Vypnout pro DAVdroid</string>
<string name="startup_dont_show_again">Již nezobrazovat</string>
<string name="startup_development_version">DAVdroid preview vydání</string>
<string name="startup_development_version_message">Toto je vývojová verze aplikace DAVdroid. Mějte na paměti, že vše nemusí správně fungovat. Budeme rádi za konstruktivní zpětnou vazbu, která pomůže vylepšit DAVdroid.</string>
<string name="startup_development_version_give_feedback">Dát zpětnou vazbu</string>
<string name="startup_donate">Open Source informace</string>
<string name="startup_donate_message">Jsme velice rádi že používáte DAVdroid, software s otevřeným zdrojovým kódem (GPLv3). Vývoj této aplikace je náročný a trval již několik tisíc hodin, velice nás potěší přispějete-li na jeho vývoj.</string>
<string name="startup_donate_now">Zobrazit stránku pro obdarování</string>
<string name="startup_donate_later">Možná později</string>
<string name="startup_google_play_accounts_removed">Informace o chybě DRM Obchodu Play</string>
<string name="startup_google_play_accounts_removed_message">Za určitých podmínek může dojít po restartu nebo aktualizaci aplikace DAVdroid k vymazání účtů kvůli chybě DRM Obchodu Play. Pokud jste postiženi touto chybou (ale pouze v tomto případě), nainstalujte prosím z Obchodu Play aplikaci \"DAVdroid JB Workaround\".</string>
<string name="startup_google_play_accounts_removed_more_info">Více informací</string>
<string name="startup_opentasks_not_installed">OpenTasks není nainstalován</string>
<string name="startup_opentasks_not_installed_message">Aplikace OpenTasks není dostupná, proto nebude DAVdroid moci synchronizovat seznam úkolů.</string>
<string name="startup_opentasks_reinstall_davdroid">Po instalaci OpenTasks musíte PŘEINSTALOVAT DAVdroid a přidat znovu své účty (Android chyba).</string>
<string name="startup_opentasks_not_installed_install">Nainstalovat OpenTasks</string>
<!--AboutActivity-->
<string name="about_license_terms">Licenční podmínky</string>
<string name="about_license_info_no_warranty">Tento program je distribuován BEZ JAKÉKOLIV ZÁRUKY. Je to volně dostupný software a lze jej za určitých podmínek dále distribuovat.</string>
<!--global settings-->
<string name="logging_davdroid_file_logging">DAVdroid logování do souboru</string>
<string name="logging_to_external_storage">Logování do externího úložiště: %s</string>
<string name="logging_to_external_storage_warning">Smazat logy jak nejdříve možno!</string>
<string name="logging_couldnt_create_file">Nelze vytvořit externí soubor logu: %s</string>
<string name="logging_no_external_storage">Externí úložiště nenalezeno</string>
<!--AccountsActivity-->
@@ -41,7 +35,6 @@
<string name="navigation_drawer_external_links">Externí odkazy</string>
<string name="navigation_drawer_website">Webová stránka</string>
<string name="navigation_drawer_faq">FAQ</string>
<string name="navigation_drawer_forums">Komunita</string>
<string name="navigation_drawer_donate">Obdarovat</string>
<string name="account_list_empty">Vítejte v aplikaci DAVdroid!\n\nNyní můžete přidat CalDAV/CardDAV účet.</string>
<!--DavService-->
@@ -53,14 +46,19 @@
<string name="app_settings_reset_hints">Resetovat nápovědu</string>
<string name="app_settings_reset_hints_summary">Znovu povolí vypnuté texty nápovědy</string>
<string name="app_settings_reset_hints_success">Budou zobrazovány všechny texty nápovědy</string>
<string name="app_settings_connection">Připojení</string>
<string name="app_settings_override_proxy">Přepsat proxy nastavení</string>
<string name="app_settings_override_proxy_on">Použít vlastní proxy nastavení</string>
<string name="app_settings_override_proxy_off">Použít výchozí systémová proxy nastavení</string>
<string name="app_settings_override_proxy_host">HTTP proxy hostname</string>
<string name="app_settings_override_proxy_port">HTTP proxy port</string>
<string name="app_settings_security">Zabezpečení</string>
<string name="app_settings_reset_trusted_certificates">Resetovat důvěryhodné certifikáty</string>
<string name="app_settings_reset_trusted_certificates_summary">Zapomene všechny dříve akceptované certifikáty</string>
<plurals name="app_settings_reset_trusted_certificates_success">
<item quantity="one">Znedůvěryhodněn jeden certifikát</item>
<item quantity="few">Znedůvěryhodněny %d certifikáty</item>
<item quantity="other">Znedůvěryhodněno %d certifikátů</item>
</plurals>
<string name="app_settings_distrust_system_certs">Nedůvěřovat systémovým certifikátům</string>
<string name="app_settings_distrust_system_certs_on">Systémovým a uživatelem přidaným CA nebude důvěřováno</string>
<string name="app_settings_distrust_system_certs_off">Systémovým a uživatelem přidaným CA bude důvěřováno (doporučeno)</string>
<string name="app_settings_reset_certificates">Resetovat (ne)důvěryhodné certifikáty</string>
<string name="app_settings_reset_certificates_summary">Resetovat důvěryhodnost všech vlastních certifikátů</string>
<string name="app_settings_reset_certificates_success">Všechny vlastní certifikáty byly resetovány</string>
<string name="app_settings_debug">Ladění</string>
<string name="app_settings_log_to_external_storage">Logovat do externího souboru</string>
<string name="app_settings_log_to_external_storage_on">Logování do externího úložiště (pokud dostupné)</string>
@@ -71,6 +69,9 @@
<string name="account_synchronize_now">Synchronizovat nyní</string>
<string name="account_synchronizing_now">Probíhá synchronizace</string>
<string name="account_settings">Nastavení účtu</string>
<string name="account_rename">Přejmenovat účet</string>
<string name="account_rename_new_name">Neuložená místní data mohou být vynechána. Po přejmenování je vyžadována nová synchronizace. Nové jméno účtu:</string>
<string name="account_rename_rename">Přejmenovat</string>
<string name="account_delete">Smazat účet</string>
<string name="account_delete_confirmation_title">Opravdu smazat účet?</string>
<string name="account_delete_confirmation_text">Všechny místní kopie adresáře, kalendářů a úkolů budou smazány.</string>
@@ -78,17 +79,6 @@
<string name="account_create_new_address_book">Vytvořit nový adresář</string>
<string name="account_refresh_calendar_list">Obnovit seznam kalendářů</string>
<string name="account_create_new_calendar">Vytvořit nový kalendář</string>
<!--PermissionsActivity-->
<string name="permissions_title">DAVdroid oprávnění</string>
<string name="permissions_calendar">Oprávnění pro kalendáře</string>
<string name="permissions_calendar_details">Pro synchronizaci CalDAV událostí s místním kalendářem potřebuje DAVdroid oprávnění přistupovat ke kalendářům.</string>
<string name="permissions_calendar_request">Vyžádat oprávnění kalendáře</string>
<string name="permissions_contacts">Oprávnění pro kontakty</string>
<string name="permissions_contacts_details">Pro synchronizaci CardDAV adresářů s místními kontakty potřebuje DAVdroid oprávnění přistupovat ke kontaktům.</string>
<string name="permissions_contacts_request">Vyžádat oprávnění kontaktů</string>
<string name="permissions_opentasks">Oprávnění pro OpenTasks</string>
<string name="permissions_opentasks_details">Pro synchronizaci CalDAV událostí s místním seznamem úkolů potřebuje DAVdroid oprávnění přistupovat k OpenTasks.</string>
<string name="permissions_opentasks_request">Vyžádat oprávnění OpenTasks</string>
<!--AddAccountActivity-->
<string name="login_title">Přidat účet</string>
<string name="login_type_email">Přihlášení s emailovou adresou</string>
@@ -102,7 +92,6 @@
<string name="login_user_name">Uživatelské jméno</string>
<string name="login_user_name_required">Vyžadováno uživatelské jméno</string>
<string name="login_base_url">Základní URL</string>
<string name="login_auth_preemptive">Preemptivní ověření (doporučeno, ale není kompatibilní s Digest ověřením)</string>
<string name="login_login">Login</string>
<string name="login_back">Zpět</string>
<string name="login_create_account">Vytvořit účet</string>
@@ -112,9 +101,8 @@
<string name="login_account_name_required">Vyžadováno jméno účtu</string>
<string name="login_account_not_created">Účet nelze vytvořit</string>
<string name="login_configuration_detection">Vyhledání konfigurace</string>
<string name="login_querying_server">Chvíli strpení, probíhá dotazování serveru...</string>
<string name="login_querying_server">Chvíli strpení, probíhá dotazování serveru</string>
<string name="login_no_caldav_carddav">Nelze nalézt službu CalDAV nebo CardDAV.</string>
<string name="login_view_logs">Prohlížet logy</string>
<!--AccountSettingsActivity-->
<string name="settings_title">Nastavení: %s</string>
<string name="settings_authentication">Ověření</string>
@@ -123,43 +111,15 @@
<string name="settings_password">Heslo</string>
<string name="settings_password_summary">Aktualizovat heslo dle svého serveru.</string>
<string name="settings_enter_password">Vložit své heslo:</string>
<string name="settings_preemptive">Preemptivní ověření</string>
<string name="settings_preemptive_on">Přihlašovací údaje jsou zasílány s každým požadavkem (doporučeno)</string>
<string name="settings_preemptive_off">Přihlašovací údaje jsou zasílány po vyžádání serverem</string>
<string name="settings_sync">Synchronizace</string>
<string name="settings_sync_interval_contacts">Interval synchronizace kontaktů</string>
<string name="settings_sync_summary_manually">Pouze manuálně</string>
<string name="settings_sync_summary_periodically" tools:ignore="PluralsCandidate">Každých %d minut a ihned při lokálních změnách</string>
<string name="settings_sync_summary_not_available">Nedostupný</string>
<string name="settings_sync_interval_calendars">Interval synchronizace kalendáře</string>
<string name="settings_sync_interval_tasks">Interval synchronizace úkolů</string>
<string-array name="settings_sync_interval_seconds">
<item>-1</item>
<item>300</item>
<item>600</item>
<item>900</item>
<item>3600</item>
<item>7200</item>
<item>14400</item>
<item>86400</item>
</string-array>
<string-array name="settings_sync_interval_names">
<item>Pouze manuálně</item>
<item>Každých 5 minut</item>
<item>Každých 10 minut</item>
<item>Každých 15 minut</item>
<item>Každou hodinu</item>
<item>Každé 2 hodiny</item>
<item>Každé 4 hodiny</item>
<item>Jednou za den</item>
</string-array>
<string name="settings_sync_wifi_only">Synchronizovat pouze přes WiFi</string>
<string name="settings_sync_wifi_only_on">Synchronizace omezena na WiFi připojení</string>
<string name="settings_sync_wifi_only_off">Druh připojení není brán v potaz</string>
<string name="settings_sync_wifi_only_ssid">Omezení WiFi SSID</string>
<string name="settings_sync_wifi_only_ssid_on">Synchronizace pouze přes %s</string>
<string name="settings_sync_wifi_only_ssid_off">Použít všechna WiFi připojení</string>
<string name="settings_sync_wifi_only_ssid_message">Zadejte jméno WiFi sítě (SSID) pro omezení synchronizace na tutu síť, nebo ponechte prázdné pro použití všech WiFi připojení.</string>
<string name="settings_carddav">CardDAV</string>
<string name="settings_contact_group_method">Metoda seskupování kontaktů</string>
<string-array name="settings_contact_group_method_values">
@@ -170,24 +130,19 @@
<item>Skupiny jsou oddělené soubory VCard</item>
<item>Skupiny jsou kategorie na kontakt</item>
</string-array>
<string name="settings_rfc6868_for_vcards">Použít RFC6868 pro VCard</string>
<string name="settings_rfc6868_for_vcards_on">Uvozovky lze použít v hodnotách parametrů</string>
<string name="settings_rfc6868_for_vcards_off">Uvozovky nelze použít v hodnotách parametrů</string>
<string name="settings_caldav">CalDAV</string>
<string name="settings_sync_time_range_past">Časový limit pro staré události</string>
<string name="settings_sync_time_range_past_none">Synchronizovat všechny události</string>
<plurals name="settings_sync_time_range_past_days">
<item quantity="one">Ignorovat události starší než 1 den</item>
<item quantity="few">Ignorovat události starší než %d dny</item>
<item quantity="many">Ignorovat události starší než %d dnů</item>
<item quantity="other">Ignorovat události starší než %d dnů</item>
</plurals>
<string name="settings_sync_time_range_past_message">Události z minulosti starší než vyznačený počet dnů budou ignorovány (lze zadat 0). Ponechte prázdné pro synchronizaci všech událostí.</string>
<string name="settings_manage_calendar_colors">Spravovat barvy kalendářů</string>
<string name="settings_manage_calendar_colors_on">Barvy kalendářů spravuje DAVdroid</string>
<string name="settings_manage_calendar_colors_off">Barvy kalendářů nespravuje DAVdroid</string>
<string name="settings_version_update">Aktualizace verze DAVdroid</string>
<string name="settings_version_update_settings_updated">Vnitřní nastavení byla aktualizována.</string>
<string name="settings_version_update_install_hint">Při problémech odinstalujte a znovu nainstalujte DAVdroid.</string>
<!--collection management-->
<string name="create_addressbook">Vytvořit adresář</string>
<string name="create_addressbook_display_name_hint">Můj adresář</string>
@@ -214,29 +169,11 @@
<string name="exception_httpexception">Došlo k HTTP chybě.</string>
<string name="exception_ioexception">Došlo k I/O chybě.</string>
<string name="exception_show_details">Zobrazit detaily</string>
<!--sync errors and DebugInfoActivity-->
<!--sync adapters and DebugInfoActivity-->
<string name="debug_info_title">Ladící informace</string>
<string name="sync_error_permissions">DAVdroid oprávnění</string>
<string name="sync_error_permissions_text">Vyžadována dodatečná oprávnění</string>
<string name="sync_error_calendar">Synchronizace kalendáře selhala (%s)</string>
<string name="sync_error_contacts">Synchronizace adresáře selhala (%s)</string>
<string name="sync_error_tasks">Synchronizace úkolu selhala (%s)</string>
<string name="sync_error">Chyba při %s</string>
<string name="sync_error_http_dav">Chyba serveru při %s</string>
<string name="sync_error_local_storage">Chyba databáze při %s</string>
<string-array name="sync_error_phases">
<item>příprava synchronizace</item>
<item>dotazování možností</item>
<item>zpracovávání místně smazaných záznamů</item>
<item>příprava vytvořených/upravených záznamů</item>
<item>nahrávání vytvořených/upravených záznamů</item>
<item>kontrola stavu synchronizace</item>
<item>výpis místních záznamů</item>
<item>výpis vzdálených záznamů</item>
<item>porovnání místních/vzdálených záznamů</item>
<item>stahování vzdálených záznamů</item>
<item>uzavírání procesu</item>
<item>ukládání stavu synchronizace</item>
</string-array>
<string name="sync_error_unauthorized">Chybné uživatelské jméno/heslo</string>
<!--cert4android-->
<string name="certificate_notification_connection_security">DAVdroid: Zabezpečení připojení</string>
<string name="trust_certificate_unknown_certificate_found">DAVdroid nalezl neznámý certifikát. Chcete mu důvěřovat?</string>
</resources>

View File

@@ -2,163 +2,165 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!--common strings-->
<string name="app_name">DAVdroid</string>
<string name="account_title_address_book">DAVdroid adressebog</string>
<string name="address_books_authority_title">Adressebøger</string>
<string name="help">Hjælp</string>
<string name="manage_accounts">Administrer konti</string>
<string name="please_wait">Vent venligst -</string>
<string name="manage_accounts">Administrere konti</string>
<string name="please_wait">Vent</string>
<string name="send">Send</string>
<string name="notification_channel_debugging">Fejlsøgning</string>
<string name="notification_channel_general">Andre vigtige beskeder</string>
<string name="notification_channel_sync">Synkronisering</string>
<string name="notification_channel_sync_errors">Synkroniserings-fejl</string>
<string name="notification_channel_sync_io_errors">Netværks- og I/O-fejl</string>
<string name="notification_channel_sync_status">Status beskeder</string>
<!--startup dialogs-->
<string name="startup_battery_optimization_disable">Deaktivere DAVdroid</string>
<string name="startup_dont_show_again">Vis ikke igen</string>
<string name="startup_development_version">DAVdroid Preview</string>
<string name="startup_development_version_message">Dette er udviklingsversionen af DAVdroid. Bemærk, at nogle ting måske ikke fungerer, som man forventer. Giv os gerne konstruktiv kritik for at forbedre DAVdroid.</string>
<string name="startup_development_version_give_feedback">Giv feedback</string>
<string name="startup_donate">Open-Source Information</string>
<string name="startup_donate">Open-Source information</string>
<string name="startup_donate_message">Det glæder os, at du bruger DAVdroid, som er open source-software (GPLv3). Det er hårdt arbejde at udvikle DAVdroid og taget tusindvis af arbejdstimer, så overvej at donere til projektet.</string>
<string name="startup_donate_now">Vis donationsside</string>
<string name="startup_donate_later">Måske senere</string>
<string name="startup_google_play_accounts_removed">Play Store DRM-fejl: Information</string>
<string name="startup_google_play_accounts_removed">Play Store DRM fejl information</string>
<string name="startup_google_play_accounts_removed_message">Under visse tekniske omstændigheder kan DRM fra Play Store bevirke, at alle DAVdroid-konti er væk efter en genstart eller opgradering af DAVdroid. Hvis du er udsat for dette problem (og ellers ikke), opfordres du til at installere DAVDroid JB Workaround\" fra Play Store.</string>
<string name="startup_google_play_accounts_removed_more_info">Yderligere oplysninger</string>
<string name="startup_more_info">Mere information</string>
<string name="startup_opentasks_not_installed">OpenTasks ikke installeret</string>
<string name="startup_opentasks_not_installed_message">OpenTasks er ikke til rådighedm så DAVdroid vil ikke kunne synkronisere opgavelister.</string>
<string name="startup_opentasks_not_installed_message">Du er nødt til at have den gratis app OpenTasks for at kunne synkronisere opgaver. (Ikke påkrævet for kontakter/begivenheder.)</string>
<string name="startup_opentasks_reinstall_davdroid">Efter at have installeret OpenTasks, vil du være nødt til at GENINSTALLERE DAVdroid og dine konti igen (en fejl i Android).</string>
<string name="startup_opentasks_not_installed_install">Installer OpenTasks</string>
<string name="startup_opentasks_not_installed_install">Installere OpenTasks</string>
<!--AboutActivity-->
<string name="about_license_terms">Licensforhold</string>
<string name="about_license_info_no_warranty">Dette program leveres ABSOLUT UDEN GARANTI. Det er fri software, og du er velkommen til at videredistribuere det under visse betingelse.</string>
<!--global settings-->
<string name="logging_davdroid_file_logging">DAVdroid fil-logning</string>
<string name="logging_to_external_storage">Logger til eksternt datalager: %s</string>
<string name="logging_to_external_storage_warning">Slet logfiler hurtigst muligt!</string>
<string name="logging_couldnt_create_file">Kunne ikke oprette ekstern logfil: %s</string>
<string name="logging_no_external_storage">Eksternt lager ikke funder</string>
<string name="logging_no_external_storage">Eksternt lager ikke fundet</string>
<!--AccountsActivity-->
<string name="navigation_drawer_open">Åbn navigationsvindue</string>
<string name="navigation_drawer_close">Luk navigationsvindue</string>
<string name="navigation_drawer_subtitle">CalDAV/CardDAV Sync-adapter</string>
<string name="navigation_drawer_about">Om / Licens</string>
<string name="navigation_drawer_settings">Indstillinger</string>
<string name="navigation_drawer_subtitle">CalDAV/CardDAV synkroniseringsadapter</string>
<string name="navigation_drawer_about">Om / licens</string>
<string name="navigation_drawer_beta_feedback">Beta tilbagemelding</string>
<string name="navigation_drawer_settings">Opsætning</string>
<string name="navigation_drawer_news_updates">Nyheder &amp; opdateringer</string>
<string name="navigation_drawer_external_links">Eksterne links</string>
<string name="navigation_drawer_website">Hjemmeside</string>
<string name="navigation_drawer_faq">FAQ</string>
<string name="navigation_drawer_forums">Community</string>
<string name="navigation_drawer_external_links">Eksterne henvisninger</string>
<string name="navigation_drawer_website">Netsted</string>
<string name="navigation_drawer_manual">Manual</string>
<string name="navigation_drawer_faq">OSS</string>
<string name="navigation_drawer_forums">Hjælp / fora</string>
<string name="navigation_drawer_donate">Donation</string>
<string name="account_list_empty">Velkommen til DAVdroid!\n\nDu kan nu tilføje en CaDAV/CardDAV-konto.</string>
<string name="account_list_empty">Velkommen til DAVdroid!\n\nDu kan nu tilføje en CalDAV/CardDAV konto.</string>
<string name="accounts_global_sync_disabled">Automatisk synkronisering på tværs af systemet er deaktiveret</string>
<string name="accounts_global_sync_enable">Aktivere</string>
<!--DavService-->
<string name="dav_service_refresh_failed">Registrering af tjeneste kunne ikke foretages</string>
<string name="dav_service_refresh_couldnt_refresh">Kunne opdatere liste over sæt</string>
<string name="dav_service_refresh_couldnt_refresh">Kunne ikke opdatere samling liste</string>
<!--AppSettingsActivity-->
<string name="app_settings">Indstillinger</string>
<string name="app_settings_user_interface">Brugerflade</string>
<string name="app_settings_reset_hints">Nulstil vejledende popups</string>
<string name="app_settings_reset_hints_summary">Genaktiverer hjælp, som er blevet lukket tidligere</string>
<string name="app_settings_reset_hints">Nulstil vejledende pop op</string>
<string name="app_settings_reset_hints_summary">Genaktivere tidligere lukket pop op</string>
<string name="app_settings_reset_hints_success">Al vejledning vil blive vist igen</string>
<string name="app_settings_connection">Forbindelse</string>
<string name="app_settings_override_proxy">Tilsidesæt proxyindstillinger</string>
<string name="app_settings_override_proxy_on">Brug brugerdefinerede proxyindstillinger</string>
<string name="app_settings_override_proxy_off">Brug systemstandard proxyindstillinger</string>
<string name="app_settings_override_proxy_host">HTTP proxy værtsnavn</string>
<string name="app_settings_override_proxy_port">HTTP proxy port</string>
<string name="app_settings_security">Sikkerhed</string>
<string name="app_settings_reset_trusted_certificates">Nulstil verificerede certifikater</string>
<string name="app_settings_reset_trusted_certificates_summary">Glemmer alle certifikater, der er blevet godkendt tidligere</string>
<plurals name="app_settings_reset_trusted_certificates_success">
<item quantity="one">Ikke-accepteret certifikat</item>
<item quantity="other">%d kke-accepterede certifikater</item>
</plurals>
<string name="app_settings_debug">Debugging</string>
<string name="app_settings_distrust_system_certs">Stol ikke på systemcertifikater</string>
<string name="app_settings_distrust_system_certs_on">System og brugertilføjede CA\'er vil ikke blive betroet</string>
<string name="app_settings_distrust_system_certs_off">System og brugertilføjede CA\'er vil blive betroet (anbefalet)</string>
<string name="app_settings_reset_certificates">Nulstil (ikke-)betroede certifikater</string>
<string name="app_settings_reset_certificates_summary">Nulstiller tilliden til brugerdefinerede certifikater</string>
<string name="app_settings_reset_certificates_success">Alle brugerdefinerede certifikater er blevet rydet</string>
<string name="app_settings_debug">Fejlsøgning</string>
<string name="app_settings_log_to_external_storage">Log til ekstern fil</string>
<string name="app_settings_log_to_external_storage_on">Logger til eksternt lager (hvis muligt)</string>
<string name="app_settings_log_to_external_storage_off">Ekstern logning deaktiveret</string>
<string name="app_settings_show_debug_info">Vis debug-info</string>
<string name="app_settings_show_debug_info">Vis fejlsøgnings information</string>
<string name="app_settings_show_debug_info_details">Vis/del software og opsætningsoplysninger</string>
<!--AccountActivity-->
<string name="account_synchronize_now">Synkroniser nu</string>
<string name="account_synchronizing_now">Synkroniserer nu</string>
<string name="account_synchronize_now">Synkronisere</string>
<string name="account_synchronizing_now">Synkroniserer</string>
<string name="account_settings">Opsætning af konti</string>
<string name="account_delete">Slet konto</string>
<string name="account_delete_confirmation_title">Ønsker du at slette konto?</string>
<string name="account_rename">Omdøbe konto</string>
<string name="account_rename_new_name">Lokaldata der ikke er gemt kan gå tabt. Eftersynkronisering er krævet efter omdøbning. Nyt kontonavn: </string>
<string name="account_rename_rename">Omdøbe</string>
<string name="account_delete">Slette konto</string>
<string name="account_delete_confirmation_title">Slette konto?</string>
<string name="account_delete_confirmation_text">Alle lokale kopier af addessebøger, kalendere og opgavelister vil blive slettet.</string>
<string name="account_refresh_address_book_list">Opdater adressebogslister</string>
<string name="account_create_new_address_book">Opret ny adressebog</string>
<string name="account_refresh_calendar_list">Opdater kalenderliste</string>
<string name="account_create_new_calendar">Opret ny kalender</string>
<!--PermissionsActivity-->
<string name="permissions_title">DAVdroid adgangsrettigheder</string>
<string name="permissions_calendar">Kalenderadgange</string>
<string name="permissions_calendar_details">For at synkronisere CalDAV-begivenheder med dine lokale kalendere, skal DAVdroid have adgang til dine kalendere.</string>
<string name="permissions_calendar_request">Anmod om kalenderadgang</string>
<string name="permissions_contacts">Kontakter: Adgangsrettigheder</string>
<string name="permissions_contacts_details">DAVdroid er nødt til at have adgang til dine kontakter, hvis CardDAV-adressebøger skal kunne synkronisere med dine kontakter.</string>
<string name="permissions_contacts_request">Anmod om adgang til kontakter</string>
<string name="permissions_opentasks">OpenTasks: Adgangsrettigheder</string>
<string name="permissions_opentasks_details">DAVdroid er nødt til at have adgang til OpenTasks, hvis CalDAV-opgaver skal kunne synkronisere med dine lokale opgavelister.</string>
<string name="permissions_opentasks_request">Anmod om adgang til OpenTasks</string>
<string name="account_carddav">CardDAV</string>
<string name="account_caldav">CalDAV</string>
<string name="account_webcal">Webcal</string>
<string name="account_synchronize_this_collection">synkronisere samling</string>
<string name="account_read_only">skrivebeskyttet</string>
<string name="account_calendar">kalender</string>
<string name="account_task_list">opgave liste</string>
<string name="account_refresh_address_book_list">Opdatere adressebogslister</string>
<string name="account_create_new_address_book">Oprette ny adressebog</string>
<string name="account_refresh_calendar_list">Opdatere kalenderliste</string>
<string name="account_create_new_calendar">Oprette ny kalender</string>
<string name="account_no_webcal_handler_found">Der er ikke fundet noget program der kan håndtere Webcal.</string>
<string name="account_install_icsdroid">Installere ICSdroid</string>
<!--AddAccountActivity-->
<string name="login_title">Tilføj konto</string>
<string name="login_type_email">Log ind med emailadresse</string>
<string name="login_email_address">Emailadresse</string>
<string name="login_email_address_error">Gyldig emailadresse påkrævet</string>
<string name="login_title">Tilføje konto</string>
<string name="login_type_email">Logge ind med e-post adresse</string>
<string name="login_email_address">E-post adresse</string>
<string name="login_email_address_error">Gyldig e-post adresse påkrævet</string>
<string name="login_password">Adgangskode</string>
<string name="login_password_required">Adgangskode påkrævet</string>
<string name="login_type_url">Log ind med URL og brugernavn</string>
<string name="login_url_must_be_http_or_https">URL skal begynde med http(s)://</string>
<string name="login_type_url">Logge ind med URL og brugernavn</string>
<string name="login_url_must_be_http_or_https">URL skal starte med http(s)://</string>
<string name="login_url_must_be_https">URL skal starte med https://</string>
<string name="login_url_host_name_required">Værtsnavn påkrævet</string>
<string name="login_user_name">Brugernavn</string>
<string name="login_user_name_required">Brugernavn påkrævet</string>
<string name="login_base_url">Basis-URL</string>
<string name="login_auth_preemptive">Forhåndsgodkendelse (preemptive authentication - anbefalet, men ikke kompatiblelt med Digest auth)</string>
<string name="login_login">Login</string>
<string name="login_base_url">Basis URL</string>
<string name="login_type_url_certificate">Logge ind med URL og klientcertifikat</string>
<string name="login_select_certificate">Vælge certifikat</string>
<string name="login_login">Logge ind</string>
<string name="login_back">Tilbage</string>
<string name="login_create_account">Opret konto</string>
<string name="login_create_account">Oprette konto</string>
<string name="login_account_name">Kontonavn</string>
<string name="login_account_name_info">Brug emailadressen som kontonavn, for Android vil bruge kontonavnet til ORGANIZER-feltet for aktiviteter, som du opretter. Du kan ikke have to konti med samme navn.</string>
<string name="login_account_contact_group_method">Gruppering af kontakter:</string>
<string name="login_account_name_required">Kontonavn påkrævet</string>
<string name="login_account_not_created">Konto kunne ikke oprettes</string>
<string name="login_configuration_detection">Check konfiguration</string>
<string name="login_querying_server">Vent, forespørger hos serveren...</string>
<string name="login_querying_server">Vent, forespørger serveren</string>
<string name="login_no_caldav_carddav">Kunne ikke finde CalDAV- eller CardDAV-tjeneste.</string>
<string name="login_view_logs">Vis logs.</string>
<!--AccountSettingsActivity-->
<string name="settings_title">Indstillinger: %s</string>
<string name="settings_authentication">Adgangsgodkendelse</string>
<string name="settings_username">Brugernavn</string>
<string name="settings_enter_username">Indtast brugernavn:</string>
<string name="settings_enter_username">Indtaste brugernavn:</string>
<string name="settings_password">Adgangskode</string>
<string name="settings_password_summary">Opdater adgangskoden, så den svarer til din server.</string>
<string name="settings_enter_password">Indtast adgangskode:</string>
<string name="settings_preemptive">Forhåndsgodkendelse</string>
<string name="settings_preemptive_on">Loginoplysninger sendes ved hver anmodning (anbefalet)</string>
<string name="settings_preemptive_off">Loginoplysninger sendes efter server anmoder om dem</string>
<string name="settings_certificate_alias">Alias for klientcertifikat</string>
<string name="settings_sync">Synkronisering</string>
<string name="settings_sync_interval_contacts">Synkroniseringsinterval for kontakter</string>
<string name="settings_sync_summary_manually">Kun manuelt</string>
<string name="settings_sync_summary_periodically" tools:ignore="PluralsCandidate">Hver %d minutter + øjeblikkeligt ved lokale ændringer</string>
<string name="settings_sync_summary_not_available">Ikke tilgængeligt</string>
<string name="settings_sync_interval_calendars">Synkroniseringsinterval for kalender</string>
<string name="settings_sync_interval_tasks">Synkroniseringsinterval for opgaver</string>
<string-array name="settings_sync_interval_seconds">
<item>-1</item>
<item>300</item>
<item>600</item>
<item>900</item>
<item>3600</item>
<item>7200</item>
<item>14400</item>
<item>86400</item>
</string-array>
<string-array name="settings_sync_interval_names">
<item>Kun manuelt</item>
<item>Hver 5. minut</item>
<item>Hver 10. minut</item>
<item>Hver 15. minut</item>
<item>En gang i timen</item>
<item>En gang hver 2. time</item>
<item>En gang hver 4. time</item>
<item>Hvert 15. minut</item>
<item>Hver halve time</item>
<item>Hver time</item>
<item>Hver 2. time</item>
<item>Hver 4. time</item>
<item>En gang om dagen</item>
</string-array>
<string name="settings_sync_wifi_only">Synkroniser kun over WiFi</string>
<string name="settings_sync_wifi_only_on">Synkronisering er begrænset til WiFi-forbindelser</string>
<string name="settings_sync_wifi_only_off">Forbindelsestypen har ingen betydning</string>
<string name="settings_sync_wifi_only_ssid">Begræsning til WiFi-SSID</string>
<string name="settings_sync_wifi_only_ssid_on">Vil kun blive synkroniseret over %s</string>
<string name="settings_sync_wifi_only_ssid_off">Alle WiFi-forbindelse vil kunne bruges</string>
<string name="settings_sync_wifi_only_ssid_message">Indtast navnet på et WiFi-netværk (SSID) for at begrænse synkronisering til dette netværk, eller efterlad feltet blank for at acceptere alle WiFi-forbindelser.</string>
<string name="settings_sync_wifi_only_ssids">WiFi SSID-begrænsning</string>
<string name="settings_sync_wifi_only_ssids_on">Synkroniserer kun over %s</string>
<string name="settings_sync_wifi_only_ssids_off">Alle WiFi-forbindelser vil blive anvendt</string>
<string name="settings_sync_wifi_only_ssids_message">Kommaseparerede navne (SSID\'er) over tilladte WiFi-netværk (efterlad blank for at bruge alle)</string>
<string name="settings_carddav">CardDAV</string>
<string name="settings_contact_group_method">Gruppering af kontakter</string>
<string-array name="settings_contact_group_method_values">
@@ -169,9 +171,8 @@
<item>Grupper er særskilte VCards</item>
<item>Grupper er kategorier pr. kontakt</item>
</string-array>
<string name="settings_rfc6868_for_vcards">Anvend RFC6868 for VCards</string>
<string name="settings_rfc6868_for_vcards_on">Dobbelte citationstegn kan bruges til at sætte parametre</string>
<string name="settings_rfc6868_for_vcards_off">Dobbelte citationstegn kan ikke bruges til at sætte parametre</string>
<string name="settings_contact_group_method_change">Skift grupperingsmetode</string>
<string name="settings_contact_group_method_change_reload_contacts">Dette kræver, at alle kontakter genindlæses. Lokale ændringer, der ikke er gemt, vil blive slettet.</string>
<string name="settings_caldav">CalDAV</string>
<string name="settings_sync_time_range_past">Tidsafgrænsning for tidligere begivenheder</string>
<string name="settings_sync_time_range_past_none">Alle begivenheder vil blive synkroniseret</string>
@@ -183,9 +184,10 @@
<string name="settings_manage_calendar_colors">Administrer farver for kalender</string>
<string name="settings_manage_calendar_colors_on">Kalenderfarver administreres af DAVdroid</string>
<string name="settings_manage_calendar_colors_off">Kalenderfarver sættes ikke fra DAVdroid</string>
<string name="settings_version_update">Versionsopdatering af DAVdroid</string>
<string name="settings_version_update_settings_updated">Interne indstillinger er blevet opdateret.</string>
<string name="settings_version_update_install_hint">Problemer? Afinstaller DAVdroid og geninstaller.</string>
<string name="settings_event_colors">Farver for begivenheder</string>
<string name="settings_event_colors_on">Synkroniser farver for begivenheder</string>
<string name="settings_event_colors_off">Synkroniser ikke farver for begivenheder</string>
<string name="settings_event_colors_off_confirm">Fjernes farver for begivenheder kan det fjerne farver, der allerede er synkroniseret.</string>
<!--collection management-->
<string name="create_addressbook">Opret adressebog</string>
<string name="create_addressbook_display_name_hint">Min adressebog</string>
@@ -207,34 +209,30 @@
<string name="delete_collection_confirm_title">Er du sikker?</string>
<string name="delete_collection_confirm_warning">DAV-sættet (%s) og dets data vil blive fjernet fra serveren.</string>
<string name="delete_collection_deleting_collection">Sletter CalDAV-sæt</string>
<string name="collection_force_read_only">Sæt skrivebeskyttet</string>
<!--ExceptionInfoFragment-->
<string name="exception">Der er opstået en fejl.</string>
<string name="exception_httpexception">Der er opstået en HTTP-fejl.</string>
<string name="exception_ioexception">Der er opstået en I/O-fejl.</string>
<string name="exception_show_details">Vis detaljer</string>
<!--sync errors and DebugInfoActivity-->
<!--sync adapters and DebugInfoActivity-->
<string name="debug_info_title">Debug-info</string>
<string name="sync_contacts_read_only_address_book">Skrivebeskyttet adressebog</string>
<plurals name="sync_contacts_local_contact_changes_discarded">
<item quantity="one">Lokal ændring slettet</item>
<item quantity="other">%d lokale ændringer slettet</item>
</plurals>
<string name="sync_error_permissions">DAVdroid-rettigheder</string>
<string name="sync_error_permissions_text">Yderligere adgang påkrævet</string>
<string name="sync_error_calendar">Synkronisering af kalenderen lykkedes ikke (%s)</string>
<string name="sync_error_contacts">Synkronisering af adressebogen lykkedes ikke (%s)</string>
<string name="sync_error_tasks">Synkronisering af opgaver lykkedes ikke (%s)</string>
<string name="sync_error">Fejl under %s</string>
<string name="sync_error_http_dav">Serverfejl under %s</string>
<string name="sync_error_local_storage">Databasefejl under %s</string>
<string-array name="sync_error_phases">
<item>forbereder synkronisering</item>
<item>checker understøttelse</item>
<item>behandler poster, der er slettet lokalt</item>
<item>behandler poster, der er blevet oprettet/redigeret</item>
<item>uploader poster, der er blevet oprettet/redigeret</item>
<item>checker synkroniseringsstatus</item>
<item>laver liste af lokale poster</item>
<item>laver lister af poster på server</item>
<item>sammenligner poster lokalt og på server</item>
<item>downloader poster på server</item>
<item>efterbehandler</item>
<item>gemmer synkroniseringsstatus</item>
</string-array>
<string name="sync_error_unauthorized">Fejl i brugernavn/adgangskode</string>
<string name="sync_error_opentasks_too_old">OpenTasks-version for gammel</string>
<string name="sync_error_opentasks_required_version">Påkrævet version: %1$s (aktuelt%2$s)</string>
<string name="sync_error_authentication_failed">Login mislykkedes (check loginoplysninger)</string>
<string name="sync_error_io">Netværks- eller I/O-fejl - %s</string>
<string name="sync_error_http_dav">HTTP-serverfejl - %s</string>
<string name="sync_error_local_storage">Lokal lagringsfejl - %s</string>
<string name="sync_error_retry">Gentag</string>
<string name="sync_error_view_item">Vis element</string>
<!--cert4android-->
<string name="certificate_notification_connection_security">DAVdroid: Forbindelsessikkerhed</string>
<string name="trust_certificate_unknown_certificate_found">DAVdroid er stødt på et ukendt certifikat. Vil du stole på det? </string>
</resources>

View File

@@ -2,33 +2,37 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!--common strings-->
<string name="app_name">DAVdroid</string>
<string name="account_title_address_book">Agenda DAVdroid</string>
<string name="address_books_authority_title">Agendas</string>
<string name="help">Ayuda</string>
<string name="manage_accounts">Administrar cuentas</string>
<string name="please_wait">Por favor, espere...</string>
<string name="please_wait">Por favor, espere</string>
<string name="send">Enviar</string>
<string name="notification_channel_debugging">Depuración</string>
<string name="notification_channel_general">Otros mensajes importantes</string>
<string name="notification_channel_sync">Sincronización</string>
<string name="notification_channel_sync_errors">Errores de sincronización</string>
<string name="notification_channel_sync_io_errors">Errores de Red y E/S</string>
<string name="notification_channel_sync_status">Mensajes de estado</string>
<!--startup dialogs-->
<string name="startup_battery_optimization_disable">Apagar para DAVdroid</string>
<string name="startup_dont_show_again">No mostrar de nuevo</string>
<string name="startup_development_version">Versión candidata final de DAVdroid</string>
<string name="startup_development_version_message">Esta es una versión de desarrollo de DAVdroid. Tenga presente que puede que no todo funcione como espera. Por favor, denos una retroalimentación constructiva para mejorar DAVdroid.</string>
<string name="startup_development_version_give_feedback">Dar retroalimentación</string>
<string name="startup_donate">Información de código abierto</string>
<string name="startup_donate_message">Nos alegra que uses DAVdroid, que es software de código abierto (GPLv3). Debido al duro trabajo que supone el desarrollo de DAVdroid y los cientos de horas de trabajo, por favor, considera hacer una donación.</string>
<string name="startup_donate_now">Mostrar página de donación</string>
<string name="startup_donate_later">Quizás luego</string>
<string name="startup_google_play_accounts_removed">Información de error de DRM de Play Store</string>
<string name="startup_google_play_accounts_removed_message">Bajo ciertas condiciones, el DRM de Play Store puede causar que todas las cuentas de DAVdroid se desconfiguren tras un reinicio o una actualización de DAVdroid. Si esto le afecta (y sólo en ese caso), por favor, instale \"DAVdroid JB Workaround\" desde Play Store.</string>
<string name="startup_google_play_accounts_removed_more_info">Más información</string>
<string name="startup_more_info">Más información</string>
<string name="startup_opentasks_not_installed">OpenTasks no está instalado</string>
<string name="startup_opentasks_not_installed_message">La aplicación OpenTasks no está disponible. DAVdroid no podrá sincronizar listas de tareas.</string>
<string name="startup_opentasks_not_installed_message">Para sincronizar tareas, la aplicación libre OpenTasks es requerida. (No necesaria para contactos/eventos.)</string>
<string name="startup_opentasks_reinstall_davdroid">Tras instalar OpenTasks, tendrás que re-instalar DAVdroid y añadir tus cuentas de nuevo (por un error de Android).</string>
<string name="startup_opentasks_not_installed_install">Instalar OpenTasks</string>
<!--AboutActivity-->
<string name="about_license_terms">Términos de la licencia</string>
<string name="about_license_info_no_warranty">Este programa viene sin NINGÚN TIPO DE GARANTÍA. Es software libre, y cualquier contribución es bienvenida y redistribuida bajo ciertas condiciones.</string>
<!--global settings-->
<string name="logging_davdroid_file_logging">Archivo de registro de DAVdroid</string>
<string name="logging_to_external_storage">Registrar en almacenamiento externo: %s</string>
<string name="logging_to_external_storage_warning">¡Eliminar todos los registros tan pronto como sea posible!</string>
<string name="logging_couldnt_create_file">No se puede crear el archivo de registro externo: %s</string>
<string name="logging_no_external_storage">Almacenamiento externo no encontrado</string>
<!--AccountsActivity-->
@@ -36,14 +40,18 @@
<string name="navigation_drawer_close">Cerrar panel de navegación</string>
<string name="navigation_drawer_subtitle">Adaptador de sincronización CalDAV/CardDAV</string>
<string name="navigation_drawer_about">Acerca de / Licencia</string>
<string name="navigation_drawer_beta_feedback">Retroalimentación Beta</string>
<string name="navigation_drawer_settings">Ajustes</string>
<string name="navigation_drawer_news_updates">Noticias y actualizaciones</string>
<string name="navigation_drawer_external_links">Enlaces externos</string>
<string name="navigation_drawer_website">Sitio web</string>
<string name="navigation_drawer_manual">Manual</string>
<string name="navigation_drawer_faq">Preguntas frequentes</string>
<string name="navigation_drawer_forums">Comunidad</string>
<string name="navigation_drawer_forums">Ayuda / Foros</string>
<string name="navigation_drawer_donate">Donar</string>
<string name="account_list_empty">Bienvenido a DAVdroid!\n\nAhora puede añadir una cuenta CalDAV/CardDAV.</string>
<string name="account_list_empty">Bienvenido a DAVdroid!\n\nAhora puedes añadir una cuenta CalDAV/CardDAV.</string>
<string name="accounts_global_sync_disabled">Sincronización automática del sistema completo está deshabilitada</string>
<string name="accounts_global_sync_enable">Activar</string>
<!--DavService-->
<string name="dav_service_refresh_failed">Falló la detección del servicio</string>
<string name="dav_service_refresh_couldnt_refresh">No se pudo refrescar lista de colección</string>
@@ -51,15 +59,21 @@
<string name="app_settings">Ajustes</string>
<string name="app_settings_user_interface">Interfaz de usuario</string>
<string name="app_settings_reset_hints">Restablecer advertencias</string>
<string name="app_settings_reset_hints_summary">Habilita las advertencias que han sido cesadas con anterioridad</string>
<string name="app_settings_reset_hints_success">Todas las advertencias serán mostradas de nuevo</string>
<string name="app_settings_reset_hints_summary">Habilita las advertencias que han sido rechazadas con anterioridad</string>
<string name="app_settings_reset_hints_success">Todas las advertencias se mostrarán nuevamente</string>
<string name="app_settings_connection">Conexión</string>
<string name="app_settings_override_proxy">Anular ajustes del proxy</string>
<string name="app_settings_override_proxy_on">Usar ajustes personalizados del proxy</string>
<string name="app_settings_override_proxy_off">Usar ajustes del proxy predefinidos por el sistema</string>
<string name="app_settings_override_proxy_host">Nombre del host del proxy HTTP</string>
<string name="app_settings_override_proxy_port">Puerto del proxy HTTP</string>
<string name="app_settings_security">Seguridad</string>
<string name="app_settings_reset_trusted_certificates">Restablecer certificados de confianza</string>
<string name="app_settings_reset_trusted_certificates_summary">Olvidar todos los certificados aceptados previamente</string>
<plurals name="app_settings_reset_trusted_certificates_success">
<item quantity="one">Retirada la confianza de un certificado</item>
<item quantity="other">Retirada la confianza de %d certificados</item>
</plurals>
<string name="app_settings_distrust_system_certs">Invalidar los certificados del sistema</string>
<string name="app_settings_distrust_system_certs_on">Los CA del sistema y los añadidos por el usuario no serán válidos</string>
<string name="app_settings_distrust_system_certs_off">Los CA del sistema y los añadidos por el usuario serán usados y de confianza (recomendado)</string>
<string name="app_settings_reset_certificates">Reiniciar certificados (in)validados</string>
<string name="app_settings_reset_certificates_summary">Reinicia la validez de todos los certificados particulares</string>
<string name="app_settings_reset_certificates_success">Todos los certificados particulares han sido limpiados</string>
<string name="app_settings_debug">Depuración</string>
<string name="app_settings_log_to_external_storage">Registrar en fichero externo</string>
<string name="app_settings_log_to_external_storage_on">Registro en almacenamiento externo (si está disponible)</string>
@@ -68,26 +82,27 @@
<string name="app_settings_show_debug_info_details">Ver/compartir detalles de software y configuración</string>
<!--AccountActivity-->
<string name="account_synchronize_now">Sincronizar ahora</string>
<string name="account_synchronizing_now">Sincronizando...</string>
<string name="account_synchronizing_now">Sincronizando</string>
<string name="account_settings">Ajustes de cuenta</string>
<string name="account_rename">Renombrar cuenta</string>
<string name="account_rename_new_name">Información local no guardada puede ser desechada. Se requiere resincronizar después de renombrar. Nuevo nombre de cuenta:</string>
<string name="account_rename_rename">Renombrar</string>
<string name="account_delete">Eliminar cuenta</string>
<string name="account_delete_confirmation_title">¿Seguro que desea eliminar la cuenta?</string>
<string name="account_delete_confirmation_text">Todas las copias locales de sus contactos, calendarios y tareas serán eliminadas.</string>
<string name="account_delete_confirmation_title">¿Seguro que deseas eliminar la cuenta?</string>
<string name="account_delete_confirmation_text">Todas las copias locales de tus contactos, calendarios y tareas serán eliminadas.</string>
<string name="account_carddav">CardDAV</string>
<string name="account_caldav">CalDAV</string>
<string name="account_webcal">Webcal</string>
<string name="account_synchronize_this_collection">sincronizar ésta colección</string>
<string name="account_read_only">solo lectura</string>
<string name="account_calendar">calendario</string>
<string name="account_task_list">lista de tareas</string>
<string name="account_refresh_address_book_list">Refrescar contactos</string>
<string name="account_create_new_address_book">Crear nueva lista de contactos</string>
<string name="account_create_new_address_book">Crear nueva agenda</string>
<string name="account_refresh_calendar_list">Refrescar calendario</string>
<string name="account_create_new_calendar">Crear nuevo calendario</string>
<!--PermissionsActivity-->
<string name="permissions_title">Permisos de DAVdroid</string>
<string name="permissions_calendar">Permisos de calendario</string>
<string name="permissions_calendar_details">Para sincronizar eventos CalDAV con sus calendarios locales, DAVdroid necesita acceder a los mismos.</string>
<string name="permissions_calendar_request">Solicitar permisos sobre calendario</string>
<string name="permissions_contacts">Permisos de contactos</string>
<string name="permissions_contacts_details">Para sincronizar libretas de contactos CadDAV con sus contactos locales, DAVdroid necesita acceder a los mismos.</string>
<string name="permissions_contacts_request">Solicitar permisos sobre contactos</string>
<string name="permissions_opentasks">Permisos de OpenTasks</string>
<string name="permissions_opentasks_details">Para sincronizar listas de tareas CalDAV con sus listas de tareas locales, DAVdroid necesita acceder a OpenTasks.</string>
<string name="permissions_opentasks_request">Solicitar permisos sobre OpenTasks</string>
<string name="account_no_webcal_handler_found">No se encontró aplicación para administrar Webcal</string>
<string name="account_install_icsdroid">Instale ICSdroid</string>
<!--AddAccountActivity-->
<string name="login_title">Añadir cuenta</string>
<string name="login_type_email">Acceder con cuenta de correo</string>
@@ -97,22 +112,24 @@
<string name="login_password_required">Contraseña requerida</string>
<string name="login_type_url">Acceder con URL y nombre de usuario</string>
<string name="login_url_must_be_http_or_https">La URL debe comenzar con http(s)://</string>
<string name="login_url_must_be_https">El URL debe comenzar con https://</string>
<string name="login_url_host_name_required">Nombre de servidor requerido</string>
<string name="login_user_name">Nombre de usuario</string>
<string name="login_user_name_required">Nombre de usuario requerido</string>
<string name="login_base_url">URL base</string>
<string name="login_auth_preemptive">Autenticación preferente (recomendado, pero incompatible con Digest auth)</string>
<string name="login_type_url_certificate">Iniciar sesión con URL y certificado del cliente</string>
<string name="login_select_certificate">Seleccionar un certificado</string>
<string name="login_login">Registrar</string>
<string name="login_back">Volver</string>
<string name="login_create_account">Crear cuenta</string>
<string name="login_account_name">Nombre de cuenta</string>
<string name="login_account_name_info">Use su dirección de correo como nombre de su cuenta puesto que Android usará el nombre de la cuenta como campo de \"organizador\" en los eventos que cree. No puede tener dos cuentas con el mismo nombre.</string>
<string name="login_account_name_info">Usa tu dirección de correo como nombre de cuenta puesto que Android usará el nombre de la cuenta como campo de \"organizador\" en los eventos que cree. No puedes tener dos cuentas con el mismo nombre.</string>
<string name="login_account_contact_group_method">Método de contacto de grupo:</string>
<string name="login_account_name_required">Nombre de cuenta requerido</string>
<string name="login_account_not_created">La cuenta no pudo ser creada</string>
<string name="login_configuration_detection">Detectar configuración</string>
<string name="login_querying_server">Por favor espere, consultando al servidor...</string>
<string name="login_no_caldav_carddav">No se pudo encontrar servicio CalDAV o CardDAV.</string>
<string name="login_view_logs">Ver registros</string>
<string name="login_querying_server">Por favor espera, consultando al servidor</string>
<string name="login_no_caldav_carddav">No se pudo encontrar el servicio CalDAV o CardDAV.</string>
<!--AccountSettingsActivity-->
<string name="settings_title">Ajustes: %s</string>
<string name="settings_authentication">Autenticación</string>
@@ -121,43 +138,32 @@
<string name="settings_password">Contraseña</string>
<string name="settings_password_summary">Actualiza la contraseña de acuerdo a tu servidor.</string>
<string name="settings_enter_password">Introduce tu contraseña:</string>
<string name="settings_preemptive">Autenticación preferente</string>
<string name="settings_preemptive_on">Las credenciales se envían en cada petición (recomendado)</string>
<string name="settings_preemptive_off">Las credenciales se envían después de que el servidor las pida</string>
<string name="settings_certificate_alias">Alias del certificado cliente</string>
<string name="settings_sync">Sincronización</string>
<string name="settings_sync_interval_contacts">Intervalo de sincronización de contactos</string>
<string name="settings_sync_summary_manually">Solo manualmente</string>
<string name="settings_sync_summary_periodically" tools:ignore="PluralsCandidate">Cada %d minutos + inmediatamente con cambios locales</string>
<string name="settings_sync_summary_not_available">No disponible</string>
<string name="settings_sync_interval_calendars">Intervalo de sincronización de calendarios</string>
<string name="settings_sync_interval_tasks">Intervalo de sincronizacion de Tasks</string>
<string-array name="settings_sync_interval_seconds">
<item>-1</item>
<item>300</item>
<item>600</item>
<item>900</item>
<item>3600</item>
<item>7200</item>
<item>14400</item>
<item>86400</item>
</string-array>
<string-array name="settings_sync_interval_names">
<item>Solo manualmente</item>
<item>Cada 5 minutos</item>
<item>Cada 10 minutos</item>
<item>Cada 15 minutos</item>
<item>Cada hora</item>
<item>Cada 2 horas</item>
<item>Cada 4 horas</item>
<item>Una vez al día</item>
</string-array>
<string name="settings_sync_wifi_only">Sincronizar sólo sobre WiFi</string>
<string name="settings_sync_wifi_only_on">La sincronización está restringida a conexiones WiFi</string>
<string name="settings_sync_wifi_only_off">Tipo de conexión no tomada en consideración</string>
<string name="settings_sync_wifi_only_ssid">Restricción WiFi SSID</string>
<string name="settings_sync_wifi_only_ssid_on">Sólo se sincronizará sobre %s</string>
<string name="settings_sync_wifi_only_ssid_off">Todas las conexiones WiFi pueden ser usadas</string>
<string name="settings_sync_wifi_only_ssid_message">Introduzca el nombre de una red WiFi (SSID) para restringir la sincronización a esta red, o deje el campo en blanco para usar todas las conexiones WiFi.</string>
<string name="settings_sync_wifi_only_off">Tipo de conexión no tenido en cuenta</string>
<string name="settings_sync_wifi_only_ssids">Restricción WiFi SSID</string>
<string name="settings_sync_wifi_only_ssids_on">Solo se sincronizará a través de %s</string>
<string name="settings_sync_wifi_only_ssids_off">Todas las conexiones WiFi serán usadas</string>
<string name="settings_sync_wifi_only_ssids_message">Nombres separados por comas (SSIDs) de redes WiFi permitidas (deje vacío para todas)</string>
<string name="settings_carddav">CardDAV</string>
<string name="settings_contact_group_method">Método de contacto de grupo</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>Los groups tienen VCards separadas</item>
<item>Los groups tienen una categoría por contacto</item>
</string-array>
<string name="settings_contact_group_method_change">Cambie método de grupo</string>
<string name="settings_contact_group_method_change_reload_contacts">Esto requiere recargar todos los contactos. Cambios locales sin guardar serán descartados.</string>
<string name="settings_caldav">CalDAV</string>
<string name="settings_sync_time_range_past">Límite de tiempo de eventos pasados</string>
<string name="settings_sync_time_range_past_none">Todos los eventos serán sincronizados</string>
@@ -165,15 +171,16 @@
<item quantity="one">Los eventos anteriores a un día serán ignorados</item>
<item quantity="other">Los eventos anteriores a %d días serán ignorados</item>
</plurals>
<string name="settings_sync_time_range_past_message">Los eventos anteriores a este número de días serán ignorados (puede ser 0). Deje en blanco el campo para sincronizar todos los eventos.</string>
<string name="settings_sync_time_range_past_message">Los eventos anteriores a este número de días serán ignorados (puede ser 0). Deja en blanco el campo para sincronizar todos los eventos.</string>
<string name="settings_manage_calendar_colors">Colores de calendario</string>
<string name="settings_manage_calendar_colors_on">Los colores de los calendarios son administrados por DAVdroid</string>
<string name="settings_manage_calendar_colors_off">Los colores de los calendarios no son establecidos por DAVdroid</string>
<string name="settings_version_update">Actualización de la versión de Android</string>
<string name="settings_version_update_settings_updated">Los ajustes internos han sido actualizados.</string>
<string name="settings_version_update_install_hint">¿Problemas? Desinstala y vuelve a instalar DAVdroid.</string>
<string name="settings_event_colors">Soporte de colores en eventos</string>
<string name="settings_event_colors_on">Sincronizar colores de eventos</string>
<string name="settings_event_colors_off">No sincronizar colores de eventos</string>
<string name="settings_event_colors_off_confirm">Desactivar colores de eventos podría remover colores de eventos ya sincronizados.</string>
<!--collection management-->
<string name="create_addressbook">Crear nueva lista de contactos</string>
<string name="create_addressbook">Crear nueva agenda</string>
<string name="create_addressbook_display_name_hint">Agendas</string>
<string name="create_calendar">Crear colección CalDAV</string>
<string name="create_calendar_display_name_hint">Mi calendario</string>
@@ -190,23 +197,33 @@
<string name="create_collection_home_set">Establecer localización:</string>
<string name="create_collection_create">Crear</string>
<string name="delete_collection">Eliminar colección</string>
<string name="delete_collection_confirm_title">¿Está seguro/a?</string>
<string name="delete_collection_confirm_title">¿Estás seguro/a?</string>
<string name="delete_collection_confirm_warning">Esta colección (%s) y toda su información será eliminada del servidor.</string>
<string name="delete_collection_deleting_collection">Eliminando colección</string>
<string name="collection_force_read_only">Forzar solo-lectura</string>
<!--ExceptionInfoFragment-->
<string name="exception">Ocurrió un error.</string>
<string name="exception_httpexception">Ha ocurrido un error HTTP.</string>
<string name="exception_ioexception">Ha ocurrido un error I/O.</string>
<string name="exception_show_details">Mostrar detalles</string>
<!--sync errors and DebugInfoActivity-->
<!--sync adapters and DebugInfoActivity-->
<string name="debug_info_title">Información de depuración</string>
<string name="sync_contacts_read_only_address_book">Libro de direcciones solo-lectura</string>
<plurals name="sync_contacts_local_contact_changes_discarded">
<item quantity="one">Cambio de contacto local descartado</item>
<item quantity="other">%d cambios de contactos locales descartados</item>
</plurals>
<string name="sync_error_permissions">Permisos de DAVdroid</string>
<string name="sync_error_permissions_text">Permisos adicionales requeridos</string>
<string name="sync_error_calendar">La sincronización de calendario falló (%s)</string>
<string name="sync_error_contacts">La sincronización de agenda falló (%s)</string>
<string name="sync_error_tasks">La sincronización de tareas falló (%s)</string>
<string name="sync_error">Error al %s</string>
<string name="sync_error_http_dav">Error de servidor al %s</string>
<string name="sync_error_local_storage">Error de base de datos al %s</string>
<string name="sync_error_unauthorized">Nombre de usuario/contraseña erróneo</string>
<string name="sync_error_opentasks_too_old">OpenTasks muy viejo</string>
<string name="sync_error_opentasks_required_version">Versión requerida: %1$s (actual %2$s)</string>
<string name="sync_error_authentication_failed">Falló la autenticación (revise credenciales de inicio de sesión)</string>
<string name="sync_error_io">Error de red o E/S %s</string>
<string name="sync_error_http_dav">Error de servidor %s</string>
<string name="sync_error_local_storage">Error de almacenamiento local %s</string>
<string name="sync_error_retry">Reintentar</string>
<string name="sync_error_view_item">Ver item</string>
<!--cert4android-->
<string name="certificate_notification_connection_security">DAVdroid: Seguridad de conexión</string>
<string name="trust_certificate_unknown_certificate_found">DAVdroid ha encontrado un certificado desconocido. ¿Quieres que sea válido?</string>
</resources>

View File

@@ -2,47 +2,46 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!--common strings-->
<string name="app_name">DAVdroid</string>
<string name="account_title_address_book">Carnet d\'adresses DAVdroid</string>
<string name="address_books_authority_title">Carnets d\'adresses</string>
<string name="help">Aide</string>
<string name="manage_accounts">Gestion des comptes</string>
<string name="please_wait">SVP attendez ...</string>
<string name="please_wait">patientez </string>
<string name="send">Envoyer</string>
<!--startup dialogs-->
<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">Pré-version de DAVdroid</string>
<string name="startup_development_version_message">Il s\'agit d\'une version de développement de DAVdroid. Il se peut que les choses ne fonctionnent pas comme prévu. Sil vous plaît faites-nous un retour pour améliorer DAVdroid.</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>
<string name="startup_donate_now">Faire un don</string>
<string name="startup_donate_later">Plus tard</string>
<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\'information</string>
<string name="startup_opentasks_not_installed">OpenTasks n\'est pas installé</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_not_installed">L\'application OpenTasks n\'est pas installée</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>
<!--AboutActivity-->
<string name="about_license_terms">Conditions d\'utilisation</string>
<string name="about_license_info_no_warranty">Ce programme est fourni sans AUCUNE GARANTIE. C\'est un logiciel libre, et vous êtes en droit de le redistribuer sous certaines conditions.</string>
<!--global settings-->
<string name="logging_davdroid_file_logging">DAVdroid fichier de journalisation</string>
<string name="logging_to_external_storage">Se connecter au stockage externe: %s</string>
<string name="logging_to_external_storage_warning">Supprimer les journaux dès que possible!</string>
<string name="logging_couldnt_create_file">Impossible de créer le fichier journal externe: %s</string>
<string name="logging_no_external_storage">Stockage externe introuvable</string>
<!--AccountsActivity-->
<string name="navigation_drawer_open">Ouvrir le tiroir de navigation</string>
<string name="navigation_drawer_close">Fermer le tiroir de navigation</string>
<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é &amp; mise à jour</string>
<string name="navigation_drawer_news_updates">Actualités &amp; 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_forums">Communauté</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-->
<string name="dav_service_refresh_failed">La détection du service a échoué</string>
<string name="dav_service_refresh_couldnt_refresh">Impossible d\'actualiser la liste de collection</string>
@@ -50,15 +49,21 @@
<string name="app_settings">Paramètres</string>
<string name="app_settings_user_interface">Interface utilisateur</string>
<string name="app_settings_reset_hints">Réinitialiser les astuces</string>
<string name="app_settings_reset_hints_summary">Réactiver les astuces qui ont été vu précédemment</string>
<string name="app_settings_reset_hints_summary">Réactiver les astuces qui ont été vues précédemment</string>
<string name="app_settings_reset_hints_success">Toutes les astuces seront affichés à nouveau</string>
<string name="app_settings_connection">Connexion</string>
<string name="app_settings_override_proxy">Ignorer les paramètres proxy</string>
<string name="app_settings_override_proxy_on">Utiliser des paramètres proxy personnalisés</string>
<string name="app_settings_override_proxy_off">Utiliser les paramètres proxy du système</string>
<string name="app_settings_override_proxy_host">Nom de l\'hôte du proxy HTTP</string>
<string name="app_settings_override_proxy_port">Port du proxy HTTP</string>
<string name="app_settings_security">Sécurité</string>
<string name="app_settings_reset_trusted_certificates">initialiser les certificats de confiance</string>
<string name="app_settings_reset_trusted_certificates_summary">Oublier tous les certificats qui ont été acceptés précédemment</string>
<plurals name="app_settings_reset_trusted_certificates_success">
<item quantity="one">Un certificat douteux</item>
<item quantity="other">%d certificats douteux</item>
</plurals>
<string name="app_settings_distrust_system_certs">voquer les certificats du système</string>
<string name="app_settings_distrust_system_certs_on">Les certificats du système et ceux ajoutés par l\'utilisateur ne seront pas dignes de confiance</string>
<string name="app_settings_distrust_system_certs_off">Les certificats du système et ceux ajoutés par l\'utilisateur seront dignes de confiance (recommandé)</string>
<string name="app_settings_reset_certificates">Réinitialiser les certificats de (non)confiance</string>
<string name="app_settings_reset_certificates_summary">Réinitialiser la confiance de tous les certificats personnalisés</string>
<string name="app_settings_reset_certificates_success">Tous les certificats personnalisés ont été effacés</string>
<string name="app_settings_debug">Débogage</string>
<string name="app_settings_log_to_external_storage">Journaliser dans un fichier externe</string>
<string name="app_settings_log_to_external_storage_on">Journaliser sur le stockage externe (si disponible)</string>
@@ -69,29 +74,28 @@
<string name="account_synchronize_now">Synchroniser maintenant</string>
<string name="account_synchronizing_now">Synchronisation en cours</string>
<string name="account_settings">Paramètres du compte</string>
<string name="account_rename">Renommer le compte</string>
<string name="account_rename_new_name">Les données locales non enregistrées pourraient être perdues. Une re-synchronisation est nécessaire après avoir renommé le compte. Nouveau nom du compte : </string>
<string name="account_rename_rename">Renommer</string>
<string name="account_delete">Supprimer le compte</string>
<string name="account_delete_confirmation_title">Voulez-vous vraiment supprimer le compte?</string>
<string name="account_delete_confirmation_text">Toutes les copies locales des carnets d\'adresses, des calendriers et des listes de tâches seront supprimées.</string>
<string name="account_refresh_address_book_list">Actualiser le carnet d\'adresse</string>
<string name="account_create_new_address_book">Créer un nouveau carnet d\'adresse</string>
<string name="account_carddav">CardDAV (les carnets d\'adresse) </string>
<string name="account_caldav">CalDAV (les agendas) </string>
<string name="account_webcal">WebCal (les anciens agenda)</string>
<string name="account_calendar">calendrier</string>
<string name="account_task_list">liste de tâche</string>
<string name="account_refresh_address_book_list">Actualiser le carnet d\'adresses</string>
<string name="account_create_new_address_book">Créer un nouveau carnet d\'adresses</string>
<string name="account_refresh_calendar_list">Actualiser le calendrier</string>
<string name="account_create_new_calendar">Créer un nouveau calendrier</string>
<!--PermissionsActivity-->
<string name="permissions_title">Autorisations DAVdroid</string>
<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_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>
<string name="permissions_opentasks_details">Pour synchroniser les tâches de CalDAV avec vos listes de tâches locales, DAVdroid a besoin d\'accéder à OpenTasks.</string>
<string name="permissions_opentasks_request">Demande d\'autorisations d\'accéder à OpenTasks</string>
<string name="account_no_webcal_handler_found">Aucune application compatible WebCal</string>
<string name="account_install_icsdroid">Installer ICSdroid</string>
<!--AddAccountActivity-->
<string name="login_title">Ajouter un compte</string>
<string name="login_type_email">Connexion avec une adresse email</string>
<string name="login_email_address">Adresse mail</string>
<string name="login_email_address_error">Une adresse e-mail valide est requis</string>
<string name="login_email_address_error">Une adresse e-mail valide est requise</string>
<string name="login_password">Mot de passe</string>
<string name="login_password_required">Mot de passe requis</string>
<string name="login_type_url">Connexion avec une URL et un nom d\'utilisateur</string>
@@ -100,18 +104,17 @@
<string name="login_user_name">Nom d\'utilisateur</string>
<string name="login_user_name_required">Nom d\'utilisateur requis</string>
<string name="login_base_url">URL de base</string>
<string name="login_auth_preemptive">Authentification préventive (recommandé, mais incompatible avec l\'authentification Digest)</string>
<string name="login_login">Se connecter</string>
<string name="login_back">Retour</string>
<string name="login_create_account">Créer un compte</string>
<string name="login_account_name">Nom du compte</string>
<string name="login_account_name_info">Utilisez votre adresse e-mail comme nom de compte car Android utilisera ce nom en tant que champ ORGANISATEUR pour les événements que vous créerez. Vous ne pouvez pas avoir deux comptes avec le même nom.</string>
<string name="login_account_contact_group_method">Méthode pour les contacts de type groupe :</string>
<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_view_logs">Voir infos de débogage</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>
<!--AccountSettingsActivity-->
<string name="settings_title">Paramètres: %s</string>
<string name="settings_authentication">Authentification</string>
@@ -120,51 +123,38 @@
<string name="settings_password">Mot de passe</string>
<string name="settings_password_summary">Mettre à jour le mot de passe </string>
<string name="settings_enter_password">Saisissez votre mot de passe :</string>
<string name="settings_preemptive">Authentification préventive</string>
<string name="settings_preemptive_on">Le nom d\'utilisateur et le mot de passe sont envoyés avec chaque requête (recommandé)</string>
<string name="settings_preemptive_off">Le nom d\'utilisateur et le mot de passe sont envoyés à la demande du serveur.</string>
<string name="settings_sync">Synchronisation</string>
<string name="settings_sync_interval_contacts">Interval de synchronisation des carnets d\'adresses</string>
<string name="settings_sync_interval_contacts">Intervalle de synchronisation des carnets d\'adresses</string>
<string name="settings_sync_summary_manually">Manuellement</string>
<string name="settings_sync_summary_periodically" tools:ignore="PluralsCandidate">Toutes les %d minutes et immédiatement après un changement local</string>
<string name="settings_sync_summary_not_available">Indisponible</string>
<string name="settings_sync_interval_calendars">Interval de synchronisation des agendas</string>
<string name="settings_sync_interval_tasks">Interval de synchronisation des tâches</string>
<string-array name="settings_sync_interval_seconds">
<item>-1</item>
<item>300</item>
<item>600</item>
<item>900</item>
<item>3600</item>
<item>7200</item>
<item>14400</item>
<item>86400</item>
</string-array>
<string name="settings_sync_interval_calendars">Intervalle de synchronisation des agendas</string>
<string name="settings_sync_interval_tasks">Intervalle de synchronisation des tâches</string>
<string-array name="settings_sync_interval_names">
<item>Manuellement</item>
<item>Toutes les 5 minutes</item>
<item>Toutes les 10 minutes</item>
<item>Toutes les 15 minutes</item>
<item>Tous les quarts d\'heure</item>
<item>Toutes les demi-heures</item>
<item>Toutes les heures</item>
<item>Toutes les 2 heures</item>
<item>Toutes les 4 heures</item>
<item>Toutes les deux heures</item>
<item>Toutes les quatre heures</item>
<item>Une fois par jour</item>
</string-array>
<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_ssid">Restriction WiFi SSID</string>
<string name="settings_sync_wifi_only_ssid_on">Sera seulement synchroniser avec %s</string>
<string name="settings_sync_wifi_only_ssid_off">Toutes les connexions WiFi peuvent être utilisées</string>
<string name="settings_sync_wifi_only_ssid_message">Entrez le nom d\'un réseau WiFi (SSID) pour restreindre la synchronisation à ce réseau, ou laisser vide pour autoriser toutes les connexions WiFi.</string>
<string name="settings_sync_wifi_only_ssids">Restriction 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">
<item>GROUP_VCARDS</item>
<item>CATEGORIES</item>
</string-array>
<string name="settings_rfc6868_for_vcards">Utiliser RFC6868 pour VCards</string>
<string name="settings_rfc6868_for_vcards_on">Les guillemets doubles peuvent être utilisés dans les valeurs de paramètre</string>
<string name="settings_rfc6868_for_vcards_off">Les guillemets doubles ne peuvent pas être utilisés dans les valeurs de paramètre</string>
<string-array name="settings_contact_group_method_entries">
<item>Les groupes sont des VCards indépendantes</item>
<item>Les groupes sont des catégories pour chacun des contacts</item>
</string-array>
<string name="settings_caldav">CalDAV</string>
<string name="settings_sync_time_range_past">Limite des événements passés</string>
<string name="settings_sync_time_range_past_none">Tous les événements seront synchronisés</string>
@@ -176,9 +166,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_version_update">Mise à jour de la version de DAVdroid</string>
<string name="settings_version_update_settings_updated">Les paramètres internes ont été mis à jour.</string>
<string name="settings_version_update_install_hint">Un problème? Désinstaller DAVdroid, puis réinstaller.</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>
@@ -205,15 +196,11 @@
<string name="exception_httpexception">Une erreur HTTP est survenue.</string>
<string name="exception_ioexception">Une erreur I/O est survenue.</string>
<string name="exception_show_details">Voir détails</string>
<!--sync errors and DebugInfoActivity-->
<!--sync adapters and DebugInfoActivity-->
<string name="debug_info_title">Infos de débogage</string>
<string name="sync_error_permissions">Autorisations DAVdroid</string>
<string name="sync_error_permissions_text">Autorisations supplémentaires demandées</string>
<string name="sync_error_calendar">Échec de la synchronisation du calendrier (%s)</string>
<string name="sync_error_contacts">Échec de la synchronisation du carnet d\'adresse (%s)</string>
<string name="sync_error_tasks">Échec de la synchronisation (%s)</string>
<string name="sync_error">Erreur durant %s</string>
<string name="sync_error_http_dav">Erreur de serveur durant %s</string>
<string name="sync_error_local_storage">Erreur de base de donnée durant %s</string>
<string name="sync_error_unauthorized">Nom d\'utilisateur ou mot de passe erroné</string>
<!--cert4android-->
<string name="certificate_notification_connection_security">DAVdroid : Sécurité de la connexion</string>
<string name="trust_certificate_unknown_certificate_found">DAVdroid a rencontré un certificat inconnu. Voulez-vous lui faire confiance?</string>
</resources>

View File

@@ -2,33 +2,46 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!--common strings-->
<string name="app_name">DAVdroid</string>
<string name="account_title_address_book">DAVdroid címjegyzék</string>
<string name="address_books_authority_title">Címjegyzékek</string>
<string name="help">Súgó</string>
<string name="manage_accounts">Fiókok kezelése</string>
<string name="please_wait">Kérjük, várjon ...</string>
<string name="please_wait">Kérjük, várjon </string>
<string name="send">Küldés</string>
<string name="notification_channel_debugging">Hibakeresés</string>
<string name="notification_channel_general">Egyéb fontos üzenetek</string>
<string name="notification_channel_sync">Szinkronizáció</string>
<string name="notification_channel_sync_errors">Szinkronizációs hibák</string>
<string name="notification_channel_sync_io_errors">Hálózati és I/O hibák</string>
<string name="notification_channel_sync_status">Státuszüzenetek</string>
<!--startup dialogs-->
<string name="startup_autostart_permission">Automatikus szinkronizálás</string>
<string name="startup_autostart_permission_message">A(z) %s gyári szoftvere gyakran blokkolja az automatikus szinkronizálást. Ebben az esetben engedélyezze a szinkronizálást az Android beállítások között.</string>
<string name="startup_battery_optimization">Időzített szinkronizálás</string>
<string name="startup_battery_optimization_message">Az eszköz korlátozni fogja a DAVdroid szinkronizálást. A szokásos DAVadroid szinkronizációs ciklus biztosítása érdekében vonja ki a DAVdroid-ot az „akkumulátorfigyelés” alól.</string>
<string name="startup_battery_optimization_disable">Kikapcsolás a DAVdroid kapcsán</string>
<string name="startup_dont_show_again">Ne jelenjen meg többet</string>
<string name="startup_development_version">DAVdroid előzetes kiadás</string>
<string name="startup_development_version_message">Ez a DAVdroid egy fejlesztői verziója. Elképzelhető, hogy nem minden működik úgy, ahogyan kellene. Ha így lenne, kérjük küldjön a tapasztaltakról visszajelzést.</string>
<string name="startup_development_version_give_feedback">Visszajelzés küldése</string>
<string name="startup_not_now">Ne most</string>
<string name="startup_donate">A forrás nyíltságával kapcsolatos információk</string>
<string name="startup_donate_message">Örülünk, hogy használja a DAVdroidot. A DAVdroid nyílt forráskódú (GPLv3) szoftver, de a fejlesztése kemény munkát jelent, már eddig több ezer munkaórát emésztett fel, ezért kérjük, fontolja meg, hogy támogassa munkánkat.</string>
<string name="startup_donate_now">Támogatás küldése</string>
<string name="startup_donate_later">Talán később</string>
<string name="startup_google_play_accounts_removed">Play Áruház DRM hibával kapcsolatos információ</string>
<string name="startup_google_play_accounts_removed_message">Bizonyos körülmények között a Play Áruház DRM okozhatja azt, hogy az eszköz újraindítását vagy a DAVdroid frissítését követően a DAVdroid fiókok eltűnnek. Amennyiben (és csak amennyiben) érinti Önt ez a probléma, telepítse a \"DAVdroid JB Workaround\" alkalmazást Play Áruházból.</string>
<string name="startup_google_play_accounts_removed_more_info">További információk</string>
<string name="startup_more_info">További információk</string>
<string name="startup_opentasks_not_installed">Az OpenTasks nincs telepítve</string>
<string name="startup_opentasks_not_installed_message">Az OpenTasks alkalmazás nincs telepítve, így a DAVdroid nem lesz képes szinkronizálni feladatlistákat.</string>
<string name="startup_opentasks_not_installed_message">A feladatok szinkronizálásához az ingyenes OpenTasks alkalmazásra van szükség. (A névjegyek és események szinkronizálásához erre nincs szükség.)</string>
<string name="startup_opentasks_reinstall_davdroid">Az OpenTasks telepítését követően újra kell telepíteni a DAVdroit alkalmazást és újra fel kell venni a fiókokat (Android hiba).</string>
<string name="startup_opentasks_not_installed_install">Az OpenTasks telepítése</string>
<!--AboutActivity-->
<string name="about_license_terms">Licencfeltételek</string>
<string name="about_libraries">Könyvtárak</string>
<string name="about_version">Verziószám:%1s (%2d)</string>
<string name="about_build_date">Fordítás ideje: %s</string>
<string name="about_flavor_info">Ennek a verziónak a terjesztése csak a Play Áruházon keresztül engedélyezett.</string>
<string name="about_license_info_no_warranty">Ehhez a program SEMMIFÉLE GARANCIA NEM JÁR. Ez a program szabad szoftver, ami a bizonyos feltételek mellett szabadon terjeszthető.</string>
<!--global settings-->
<string name="logging_davdroid_file_logging">DAVdroid fájlalapú naplózás</string>
<string name="logging_to_external_storage">Naplózás külső tárhelyre: %s</string>
<string name="logging_to_external_storage_warning">Törölje a naplófájlt, amint lehetséges!</string>
<string name="logging_couldnt_create_file">Külső naplófájl létrehozása sikertelen: %s</string>
<string name="logging_no_external_storage">A külső tárhely nem érhető el</string>
<!--AccountsActivity-->
@@ -36,14 +49,18 @@
<string name="navigation_drawer_close">Navigációs fiók lezárása</string>
<string name="navigation_drawer_subtitle">CalDAV/CardDAV szinkronizációs adapter</string>
<string name="navigation_drawer_about">Névjegy / Licenc</string>
<string name="navigation_drawer_beta_feedback">Tesztelői visszajelzés</string>
<string name="navigation_drawer_settings">Beállítások</string>
<string name="navigation_drawer_news_updates">Hírek és frissítések</string>
<string name="navigation_drawer_external_links">Weblapok</string>
<string name="navigation_drawer_website">Honlap</string>
<string name="navigation_drawer_manual">Kézikönyv</string>
<string name="navigation_drawer_faq">GYIK</string>
<string name="navigation_drawer_forums">Közösség</string>
<string name="navigation_drawer_forums">Segítség / Fórumok</string>
<string name="navigation_drawer_donate">Támogatás</string>
<string name="account_list_empty">Üdvözöljük a DAVdroid felhasználók között!\n\nMost már felvehet CalDAV/CardDav fiókokat.</string>
<string name="accounts_global_sync_disabled">A rendszerszintű automatikus szinkronizálás ki van kapcsolva</string>
<string name="accounts_global_sync_enable">Bekapcsolás</string>
<!--DavService-->
<string name="dav_service_refresh_failed">Szolgáltatások felderítése nem sikerült</string>
<string name="dav_service_refresh_couldnt_refresh">Gyűjteménylista frissítése nem sikerült</string>
@@ -53,13 +70,19 @@
<string name="app_settings_reset_hints">Tippek visszaállítása</string>
<string name="app_settings_reset_hints_summary">Újra jelenjen meg az összes tipp</string>
<string name="app_settings_reset_hints_success">Az összes tipp újra meg fog jelenni</string>
<string name="app_settings_connection">Kapcsolat</string>
<string name="app_settings_override_proxy">Proxybeállítások felülírása</string>
<string name="app_settings_override_proxy_on">Egyedi proxybeállítások</string>
<string name="app_settings_override_proxy_off">Az alapértelmezett proxybeállítás használata</string>
<string name="app_settings_override_proxy_host">HTTP proxyállomás neve</string>
<string name="app_settings_override_proxy_port">HTTP proxy port</string>
<string name="app_settings_security">Biztonság</string>
<string name="app_settings_reset_trusted_certificates">A tanúsítványtár visszaállítása</string>
<string name="app_settings_reset_trusted_certificates_summary">Az összes korábban megbízhatónak kiválasztott tanúsítvány törlése</string>
<plurals name="app_settings_reset_trusted_certificates_success">
<item quantity="one">Egy tanúsítvány megbízhatósága törölve</item>
<item quantity="other">%d tanúsítvány megbízhatósága törölve</item>
</plurals>
<string name="app_settings_distrust_system_certs">A rendszertanúsítványok elfogadása</string>
<string name="app_settings_distrust_system_certs_on">A rendszer által kezelt, előre vagy felhasználó által telepített tanúsítványok figyelmen kívül lesznek hagyva</string>
<string name="app_settings_distrust_system_certs_off">A rendszer által kezelt, előre vagy felhasználó által telepített tanúsítványok megbízhatóak (javasolt)</string>
<string name="app_settings_reset_certificates">A tanúsítványok megbízhatóságának törlésére</string>
<string name="app_settings_reset_certificates_summary">A tanúsítványok megbízhatóságával kapcsolatos beállítások törlésére</string>
<string name="app_settings_reset_certificates_success">A tanúsítványok megbízhatóságával kapcsolatos beállítások törölve</string>
<string name="app_settings_debug">Hibakeresés</string>
<string name="app_settings_log_to_external_storage">Naplózás fájlba</string>
<string name="app_settings_log_to_external_storage_on">Naplózás külső tárhelyre (ha elérhető)</string>
@@ -70,24 +93,26 @@
<string name="account_synchronize_now">Szinkronizálás most</string>
<string name="account_synchronizing_now">Szinkronizálás</string>
<string name="account_settings">Fiókbeállítások</string>
<string name="account_rename">Fiók átnevezése</string>
<string name="account_rename_new_name">Az elmentetlen helyben tárolt adatok elvesznek. Az átnevezés után szinkronizálásra lesz szükség. Új fióknév:</string>
<string name="account_rename_rename">Átnevez</string>
<string name="account_delete">Fiók törlése</string>
<string name="account_delete_confirmation_title">Valóban törölni akarja a fiókot?</string>
<string name="account_delete_confirmation_text">Az összes címjegyzék, naptár és feladatlista helyi példányai törölve lesznek.</string>
<string name="account_select_collections_hint">Válassza ki a szinkronizálandó gyűjteményeket</string>
<string name="account_carddav">CardDAV</string>
<string name="account_caldav">CalDAV</string>
<string name="account_webcal">Webcal</string>
<string name="account_synchronize_this_collection">a gyűjtemény szinkronizálása</string>
<string name="account_read_only">csak olvasható</string>
<string name="account_calendar">naptár</string>
<string name="account_task_list">feladatlista</string>
<string name="account_refresh_address_book_list">Címjegyzék-lista frissítése</string>
<string name="account_create_new_address_book">Új címjegyzék létrehozása</string>
<string name="account_refresh_calendar_list">Naptárlista frissítése</string>
<string name="account_create_new_calendar">Új naptár létrehozása</string>
<!--PermissionsActivity-->
<string name="permissions_title">DAVdroid engedélyek </string>
<string name="permissions_calendar">Naptárengedély</string>
<string name="permissions_calendar_details">A CalDAV naptárak és a helyi naptárak szinkronizálásához a DAVdroid naptárhozzáférést igényel.</string>
<string name="permissions_calendar_request">Naptárhozzáférés igénylése</string>
<string name="permissions_contacts">Névjegyengedélyek</string>
<string name="permissions_contacts_details">A CardDAV címlisták és a helyi címlisták szinkronizálásához a névjegyhozzáférést igényel.</string>
<string name="permissions_contacts_request">Névjegyengedélyek igénylése</string>
<string name="permissions_opentasks">OpenTasks engedélyek</string>
<string name="permissions_opentasks_details">A CalDAV feladatlisták és a helyi feladatlisták szinkronizálásához a DAVdroid OpenTasks hozzáférést igényel.</string>
<string name="permissions_opentasks_request">OpenTasks engedélyek igénylése</string>
<string name="account_no_webcal_handler_found">Nem található Webcal-képes alkalmazás</string>
<string name="account_install_icsdroid">ICSdroid telepítése</string>
<!--AddAccountActivity-->
<string name="login_title">Fiók hozzáadása</string>
<string name="login_type_email">Bejelentkezés email cím segítségével</string>
@@ -97,11 +122,13 @@
<string name="login_password_required">A jelszó megadása szükséges</string>
<string name="login_type_url">Bejelentkezés URL és felhasználónév segítségével</string>
<string name="login_url_must_be_http_or_https">Az URL elején szerepeljen http(s)://</string>
<string name="login_url_must_be_https">Az URL elején szerepeljen https://</string>
<string name="login_url_host_name_required">A szervernév megadása feltétlenül szükséges</string>
<string name="login_user_name">Felhasználónév</string>
<string name="login_user_name_required">A felhasználónév megadása feltétlenül szükséges</string>
<string name="login_base_url">URL-törzs</string>
<string name="login_auth_preemptive">Preemptív authentikáció (ajánlott, de Digest authentikációval nem működik)</string>
<string name="login_type_url_certificate">Bejelentkezés URL és tanúsítvány segítségével</string>
<string name="login_select_certificate">Tanúsítvány kiválasztása</string>
<string name="login_login">Bejelentkezés</string>
<string name="login_back">Vissza</string>
<string name="login_create_account">Fiók létrehozása</string>
@@ -111,9 +138,9 @@
<string name="login_account_name_required">A fióknév megadása feltétlenül szükséges</string>
<string name="login_account_not_created">A fiók létrehozása nem sikerült</string>
<string name="login_configuration_detection">A konfiguráció felderítése</string>
<string name="login_querying_server">Kérjük, várjon, a szerver lekérdezése...</string>
<string name="login_querying_server">Kérjük, várjon, a szerver lekérdezése</string>
<string name="login_no_caldav_carddav">Nem található CalDAV vagy CardDAV szolgáltatás.</string>
<string name="login_view_logs">Naplóbejegyzések megtekintése</string>
<string name="login_view_logs">Részletek mutatása</string>
<!--AccountSettingsActivity-->
<string name="settings_title">Beállítások: %s</string>
<string name="settings_authentication">Authentikáció</string>
@@ -122,52 +149,41 @@
<string name="settings_password">Jelszó</string>
<string name="settings_password_summary">Adja meg a szerveren érvényes új jelszót.</string>
<string name="settings_enter_password">Adja meg a jelszót:</string>
<string name="settings_preemptive">Preemptív authentikáció</string>
<string name="settings_preemptive_on">A hitelesítő adatok elküldése minden kérésnél (ajánlott)</string>
<string name="settings_preemptive_off">A hitelesítő adatok elküldése, csak ha a szerver azt igényli</string>
<string name="settings_certificate_alias">Tanúsítvány alternatív megnevezése</string>
<string name="settings_sync">Szinkronizálás</string>
<string name="settings_sync_interval_contacts">Névjegyszinkronizálás sűrűsége</string>
<string name="settings_sync_summary_manually">Manuális</string>
<string name="settings_sync_summary_periodically" tools:ignore="PluralsCandidate">Minden %d percben + az eszközön történt módosítás után</string>
<string name="settings_sync_summary_not_available">Nem elérhető</string>
<string name="settings_sync_interval_calendars">Naptárszinkronizálás sűrűsége</string>
<string name="settings_sync_interval_tasks">Feladatlisták szinkronizálásának sűrűsége</string>
<string-array name="settings_sync_interval_seconds">
<item>-1</item>
<item>300</item>
<item>600</item>
<item>900</item>
<item>3600</item>
<item>7200</item>
<item>14400</item>
<item>86400</item>
</string-array>
<string-array name="settings_sync_interval_names">
<item>Manuális</item>
<item>5 percenként</item>
<item>10 percenként</item>
<item>Manális</item>
<item>15 percenként</item>
<item>30 percenként</item>
<item>Óránként</item>
<item>2 óránként</item>
<item>4 óránként</item>
<item>Kétóránként</item>
<item>Négyóránként</item>
<item>Naponta</item>
</string-array>
<string name="settings_sync_wifi_only">Szinkronizálás csak WIFI-n</string>
<string name="settings_sync_wifi_only_on">Csak WIFI kapcsolat keresztül történjen szinkronizálás</string>
<string name="settings_sync_wifi_only_off">Szinkronizálás a kapcsolat típusától függetlenül</string>
<string name="settings_sync_wifi_only_ssid">WIFI SSID szűkítés</string>
<string name="settings_sync_wifi_only_ssid_on">Szinkronizálás csak a(z) %s hálózatra kapcsolódva</string>
<string name="settings_sync_wifi_only_ssid_off">Szinkronizálás bármely WIFI hálózaton</string>
<string name="settings_sync_wifi_only_ssid_message">Adja meg a WIFI hálózat nevét (SSID) a szinkronizálás egy hálózatra való korlátozához, vagy hagyja üresen, ha nem akar ilyen szűkítést.</string>
<string name="settings_sync_wifi_only_ssids">WiFi SSID szűrés</string>
<string name="settings_sync_wifi_only_ssids_on">Az alábbi hálózatok használhatók: %s</string>
<string name="settings_sync_wifi_only_ssids_off">Minden hálózat használható</string>
<string name="settings_sync_wifi_only_ssids_message">A használható WiFi hálózatok nevei (SSID), vesszővel elválasztva (hagyja üresen, ha nem akar szűrést beállítani)</string>
<string name="settings_carddav">CardDAV</string>
<string name="settings_contact_group_method">A csoportok kezelésének módja</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>Minden csoport egy különálló VCard</item>
<item>A csoportok a kapcsolatonkéni kategóriák</item>
</string-array>
<string name="settings_rfc6868_for_vcards">RFC6868 szabványnak megfelelő VCards használata</string>
<string name="settings_rfc6868_for_vcards_on">A paraméterértékek tartalmazhatnak idézőjelet</string>
<string name="settings_rfc6868_for_vcards_off">A paraméterértékek nem tartalmazhatnak idézőjelet</string>
<string name="settings_contact_group_method_change">A csoportok kezelésének megváltoztatása</string>
<string name="settings_contact_group_method_change_reload_contacts">Az összes névjegyet újra be kell olvasni. Az el nem mentett helyi változások törlődni fognak.</string>
<string name="settings_caldav">CalDAV</string>
<string name="settings_sync_time_range_past">Múltbéli események időkorlátja</string>
<string name="settings_sync_time_range_past_none">Minden esemény szinkronizálása</string>
@@ -179,9 +195,10 @@
<string name="settings_manage_calendar_colors">Naptárszínek kezelése</string>
<string name="settings_manage_calendar_colors_on">A naptárszíneket a DAVdroid kezeli</string>
<string name="settings_manage_calendar_colors_off">A naptárszíneket nem a DAVdroid kezeli</string>
<string name="settings_version_update">DAVdroid frissítése</string>
<string name="settings_version_update_settings_updated">A belső beállítások frissítve lettek.</string>
<string name="settings_version_update_install_hint">Probléma? Próbálja meg törölni majd újratelepíteni a DAVdroid-ot.</string>
<string name="settings_event_colors">Eseményszínek támogatása</string>
<string name="settings_event_colors_on">Eseményszínek szinkronlzálása</string>
<string name="settings_event_colors_off">Az eseményszínek szinkronizálásának elhagyása</string>
<string name="settings_event_colors_off_confirm">A szinkronizálás kikapcsolása a már szinkronizált eseményszíneket törölheti.</string>
<!--collection management-->
<string name="create_addressbook">Címjegyzék létrehozása</string>
<string name="create_addressbook_display_name_hint">Új címjegyzék</string>
@@ -203,34 +220,33 @@
<string name="delete_collection_confirm_title">Biztos?</string>
<string name="delete_collection_confirm_warning">A gyűjtemény (%s) és a hozzá tartozó adatok törölve lesznek a szerverről.</string>
<string name="delete_collection_deleting_collection">Gyűjtemény törlése</string>
<string name="collection_force_read_only">Csak olvashatóvá tétel</string>
<string name="collection_properties">Tulajdonságok</string>
<string name="collection_properties_url">Cím (URL):</string>
<string name="collection_properties_copy_url">URL másolása</string>
<!--ExceptionInfoFragment-->
<string name="exception">Hiba történt.</string>
<string name="exception_httpexception">HTTP hiba történt.</string>
<string name="exception_ioexception">I/O hiba történt.</string>
<string name="exception_show_details">Részletek megjelenítése</string>
<!--sync errors and DebugInfoActivity-->
<!--sync adapters and DebugInfoActivity-->
<string name="debug_info_title">Hibakeresési információ</string>
<string name="sync_contacts_read_only_address_book">Csak olvasható címjegyzék</string>
<plurals name="sync_contacts_local_contact_changes_discarded">
<item quantity="one">Helyi névjegyváltozás elvetve</item>
<item quantity="other">%d helyi névjegyváltozás elvetve</item>
</plurals>
<string name="sync_error_permissions">DAVdroid engedélyek </string>
<string name="sync_error_permissions_text">További engedélyek szükségesek</string>
<string name="sync_error_calendar">A naptár szinkronizálása nem sikerült (%s)</string>
<string name="sync_error_contacts">A címjegyzék szinkronizálása nem sikerült (%s)</string>
<string name="sync_error_tasks">A feladatok szinkronizálása nem sikerült (%s)</string>
<string name="sync_error">Hiba az alábbi művelet közben: %s</string>
<string name="sync_error_http_dav">Szerver oldali hiba az alábbi művelet közben: %s</string>
<string name="sync_error_local_storage">Adatbázishiba az alábbi művelet közben: %s</string>
<string-array name="sync_error_phases">
<item>szinkronizáció előkészítése </item>
<item>szerver képességeinek lekérdezése</item>
<item>a helyben törölt bejegyzések feldolgozása</item>
<item>az új vagy módosított bejegyzések gyűjtése </item>
<item>az új vagy módosított bejegyzések feltöltése</item>
<item>szinkronizációs állapot ellenőrzése</item>
<item>helyi bejegyzések listázása</item>
<item>távoli bejegyzések listázása</item>
<item>helyi és távoli bejegyzések összehasonlítása</item>
<item>távoli bejegyzések letöltése</item>
<item>utófeldolgozás</item>
<item>szinkronizációs állapot mentése</item>
</string-array>
<string name="sync_error_unauthorized">A felhasználónév vagy jelszó hibás</string>
<string name="sync_error_opentasks_too_old">Az OpenTask verzió nem megfelelő</string>
<string name="sync_error_opentasks_required_version">Szükséges verzió: %1$s (jelenlegi verzió: %2$s)</string>
<string name="sync_error_authentication_failed">Authentikáció nem sikerült (ellenőrizze a hitelesítéshez megadott adatokat)</string>
<string name="sync_error_io">Hálózati vagy I/O hiba %s</string>
<string name="sync_error_http_dav">HTTP szerver oldali hiba - %s</string>
<string name="sync_error_local_storage">Tárhelyhiba - %s</string>
<string name="sync_error_retry">Újbóli próbálkozás</string>
<string name="sync_error_view_item">Elem megtekintése</string>
<!--cert4android-->
<string name="certificate_notification_connection_security">DAVdroid: kapcsolatbiztonság</string>
<string name="trust_certificate_unknown_certificate_found">Egy eddig ismeretlen tanúsítvány érkezett. Megbízhatónak kívánja elfogadni?</string>
</resources>

View File

@@ -0,0 +1,219 @@
<?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">Rubrica DAVdroid</string>
<string name="address_books_authority_title">Rubriche</string>
<string name="help">Aiuto</string>
<string name="manage_accounts">Gestione account</string>
<string name="please_wait">Attendere prego …</string>
<string name="send">Invia</string>
<string name="notification_channel_general">Altri messaggi importanti</string>
<string name="notification_channel_sync">Sincronizzazione</string>
<string name="notification_channel_sync_errors">Errori di sincronizzazione</string>
<string name="notification_channel_sync_io_errors">Errori di Rete e di I/O</string>
<string name="notification_channel_sync_status">Messaggi di stato</string>
<!--startup dialogs-->
<string name="startup_battery_optimization_disable">Disabilita per DAVdroid</string>
<string name="startup_dont_show_again">Non mostrare più</string>
<string name="startup_donate">Informazioni sull\'Open-Source</string>
<string name="startup_donate_message">Siamo soddisfatti del tuo uso di DAVdroid, programma Open-Source (GPLv3). Poiché lo sviluppo è un\'iniziativa complessa che comporta molte ore di lavoro ti invitiamo a fare una donazione.</string>
<string name="startup_donate_now">Mostra pagina donazioni</string>
<string name="startup_donate_later">Più tardi</string>
<string name="startup_google_play_accounts_removed">Informazioni sul bug del DRM di Play Store</string>
<string name="startup_google_play_accounts_removed_message">In alcune condizioni il DRM di Play Store può causare la perdita di tutti gli account DAVdroid dopo un riavvio o dopo un aggiornamento di DAVdroid. Se verificate questo problema installate successivamente \"DAVdroid JB Workaround\" da Play Store.</string>
<string name="startup_more_info">Più informazioni</string>
<string name="startup_opentasks_not_installed">OpenTasks non installata</string>
<string name="startup_opentasks_not_installed_message">Per sincronizzare le attività è richiesta l\'app gratuita OpenTasks. (Non richiesta per contatti/eventi.)</string>
<string name="startup_opentasks_reinstall_davdroid">Dopo l\'installazione di OpenTasks è necessario INSTALLARE NUOVAMENTE DAVdroid e aggiungere ancora gli account (per un bug di Android).</string>
<string name="startup_opentasks_not_installed_install">Installa OpenTasks</string>
<!--AboutActivity-->
<string name="about_license_info_no_warranty">Il programma è distribuito SENZA ALCUNA GARANZIA. È software libero e può essere redistribuito sotto alcune condizioni.</string>
<!--global settings-->
<string name="logging_davdroid_file_logging">Invio del log di DAVdroid su file</string>
<string name="logging_to_external_storage">Log su dispositivo esterno: %s</string>
<string name="logging_couldnt_create_file">Non riesco a creare il file di log esterno: %s</string>
<string name="logging_no_external_storage">Dispositivo esterno non disponibile</string>
<!--AccountsActivity-->
<string name="navigation_drawer_open">Apri barra di navigazione</string>
<string name="navigation_drawer_close">Chiudi barra di navigazione</string>
<string name="navigation_drawer_subtitle">CalDAV/CardDAV adattatore di sincronizzazione</string>
<string name="navigation_drawer_about">Informazioni / Licenza</string>
<string name="navigation_drawer_settings">Impostazioni</string>
<string name="navigation_drawer_news_updates">Notizie &amp; aggiornamenti</string>
<string name="navigation_drawer_external_links">Link esterni</string>
<string name="navigation_drawer_website">Sito web</string>
<string name="navigation_drawer_manual">Manuale</string>
<string name="navigation_drawer_faq">Domande Frequenti</string>
<string name="navigation_drawer_forums">Aiuto / Forum</string>
<string name="navigation_drawer_donate">Donazione</string>
<string name="account_list_empty">Benvenuto a DAVdroid!\n\nÈ ora possibile aggiungere account CalDAV/CardDAV.</string>
<string name="accounts_global_sync_disabled">La sincronizzazione automatica dell\'intero sistema è disabilitata</string>
<string name="accounts_global_sync_enable">Attiva</string>
<!--DavService-->
<string name="dav_service_refresh_failed">Fallita l\'individuazione dei servizi</string>
<string name="dav_service_refresh_couldnt_refresh">Impossibile aggiornare la lista delle raccolte</string>
<!--AppSettingsActivity-->
<string name="app_settings">Impostazioni</string>
<string name="app_settings_user_interface">Interfaccia utente</string>
<string name="app_settings_reset_hints">Reimposta i suggerimenti</string>
<string name="app_settings_reset_hints_summary">Riabilita i suggerimenti precedentemente disabilitati</string>
<string name="app_settings_reset_hints_success">I suggerimenti verranno mostrati</string>
<string name="app_settings_connection">Connessione</string>
<string name="app_settings_override_proxy">Non rispettare la impostazioni del proxy</string>
<string name="app_settings_override_proxy_on">Impostazioni personalizzate del proxy</string>
<string name="app_settings_override_proxy_off">Usa le impostazioni di sistema del proxy</string>
<string name="app_settings_override_proxy_host">Nome host del proxy HTTP</string>
<string name="app_settings_override_proxy_port">Porta del proxy HTTP</string>
<string name="app_settings_security">Sicurezza</string>
<string name="app_settings_distrust_system_certs">Non ti fidare dei certificati di sistema</string>
<string name="app_settings_distrust_system_certs_on">Le CA di sistema e quelle aggiunte dall\'utente non sono affidabili</string>
<string name="app_settings_distrust_system_certs_off">Le CA di sistema e quelle aggiunte dall\'utente sono affidabili (raccomandato)</string>
<string name="app_settings_reset_certificates">Reimposta la fiducia in tutti i certificati</string>
<string name="app_settings_reset_certificates_summary">Reimposta la fiducia nei certificati aggiunti</string>
<string name="app_settings_reset_certificates_success">Sono stati cancellati tutti i certificati aggiunti</string>
<string name="app_settings_debug">Debug</string>
<string name="app_settings_log_to_external_storage">Log su file esterno</string>
<string name="app_settings_log_to_external_storage_on">Log su dispositivo esterno (se disponibile)</string>
<string name="app_settings_log_to_external_storage_off">Log su file esterno disabilitato</string>
<string name="app_settings_show_debug_info">Mostra informazioni di debug</string>
<string name="app_settings_show_debug_info_details">Mostra e condividi i dettagli del programma e della configurazione</string>
<!--AccountActivity-->
<string name="account_synchronize_now">Sincronizza adesso</string>
<string name="account_synchronizing_now">Sincronizzazione in corso</string>
<string name="account_settings">Impostazioni account</string>
<string name="account_rename">Rinomina account</string>
<string name="account_rename_new_name">I dati locali non salvati potrebbero essere rimossi. È necessario effettuare la risincronizzazione dopo la rinomina. Nuovo nome dell\'account:</string>
<string name="account_rename_rename">Rinomina</string>
<string name="account_delete">Elimina account</string>
<string name="account_delete_confirmation_title">Cancellare l\'account?</string>
<string name="account_delete_confirmation_text">Tutte le copie locali delle rubriche, dei calendari e degli elenchi attività verranno eliminate.</string>
<string name="account_carddav">CardDAV</string>
<string name="account_caldav">CalDAV</string>
<string name="account_webcal">Webcal</string>
<string name="account_read_only">sola lettura</string>
<string name="account_calendar">calendario</string>
<string name="account_task_list">elenco attività</string>
<string name="account_refresh_address_book_list">Aggiorna elenco degli indirizzari</string>
<string name="account_create_new_address_book">Crea un nuovo indirizzario</string>
<string name="account_refresh_calendar_list">Aggiorna lista calendari</string>
<string name="account_create_new_calendar">Crea nuovo calendario</string>
<string name="account_install_icsdroid">Installa ICSdroid</string>
<!--AddAccountActivity-->
<string name="login_title">Aggiungi account</string>
<string name="login_type_email">Accedi con indirizzo email</string>
<string name="login_email_address">Indirizzo email</string>
<string name="login_email_address_error">È necessario un indirizzo email valido</string>
<string name="login_password">Password</string>
<string name="login_password_required">Password richiesta</string>
<string name="login_type_url">Accedi con URL e nome utente</string>
<string name="login_url_must_be_http_or_https">L\'URL deve iniziare con http(s)://</string>
<string name="login_url_must_be_https">L\'URL deve iniziare con https://</string>
<string name="login_url_host_name_required">Nome host richiesto</string>
<string name="login_user_name">Nome utente</string>
<string name="login_user_name_required">Nome utente richiesto</string>
<string name="login_base_url">Base URL</string>
<string name="login_type_url_certificate">Accedi con URL e certificato client</string>
<string name="login_select_certificate">Seleziona certificato</string>
<string name="login_login">Login</string>
<string name="login_back">Indietro</string>
<string name="login_create_account">Crea account</string>
<string name="login_account_name">Nome account</string>
<string name="login_account_name_info">Inserisci il tuo indirizzo email come nome dell\'account in quanto Android userà il nome dell\'account nel campo ORGANIZER degli eventi creati. Non è possibile avere due account con nome uguale.</string>
<string name="login_account_contact_group_method">Metodo del contact group:</string>
<string name="login_account_name_required">Richiesto il nome dell\'account</string>
<string name="login_account_not_created">L\'account non può essere creato</string>
<string name="login_configuration_detection">Rilevazione configurazione</string>
<string name="login_querying_server">Attendere, invio richiesta al server…</string>
<string name="login_no_caldav_carddav">Impossibile trovare servizi CalDAV o CardDAV.</string>
<!--AccountSettingsActivity-->
<string name="settings_title">Impostazioni: %s</string>
<string name="settings_authentication">Autenticazione</string>
<string name="settings_username">Nome utente</string>
<string name="settings_enter_username">Inserisci nome utente:</string>
<string name="settings_password">Password</string>
<string name="settings_password_summary">Aggiorna la password come sul tuo server.</string>
<string name="settings_enter_password">Inserisci la tua password:</string>
<string name="settings_sync">Sincronizzazione</string>
<string name="settings_sync_interval_contacts">Intervallo sincr. Contatti</string>
<string name="settings_sync_summary_manually">Solo manualmente</string>
<string name="settings_sync_summary_periodically" tools:ignore="PluralsCandidate">Ogni %d minuti e a seguito di ogni cambiamento locale</string>
<string name="settings_sync_interval_calendars">Intervallo sincr. calendari</string>
<string name="settings_sync_interval_tasks">Intervallo sincr. attività</string>
<string-array name="settings_sync_interval_names">
<item>Solo manualmente</item>
<item>Ogni 15 minuti</item>
<item>Ogni 30 minuti</item>
<item>Ogni ora</item>
<item>Ogni 2 ore</item>
<item>Ogni 4 ore</item>
<item>Una volta al giorno</item>
</string-array>
<string name="settings_sync_wifi_only">Sincr. solo tramite WiFi</string>
<string name="settings_sync_wifi_only_on">La sincronizzazione è limitata alle connessioni WiFi</string>
<string name="settings_sync_wifi_only_off">Il tipo di connessione non è preso in considerazione</string>
<string name="settings_sync_wifi_only_ssids">Restrizione SSID WiFi</string>
<string name="settings_sync_wifi_only_ssids_message">Nomi (SSID) delle reti WiFi autorizzate separati da virgola (lascia vuoto per autorizzarle tutte)</string>
<string name="settings_carddav">CardDAV</string>
<string name="settings_contact_group_method">Organizzazione dei gruppi di contatto</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>I gruppi sono VCards separate</item>
<item>I gruppi sono categorie per ogni contatto</item>
</string-array>
<string name="settings_caldav">CalDAV</string>
<string name="settings_sync_time_range_past">Limite di tempo per gli eventi trascorsi</string>
<string name="settings_sync_time_range_past_none">Verranno sincronizzati tutti gli eventi</string>
<plurals name="settings_sync_time_range_past_days">
<item quantity="one">Eventi più vecchi di un giorno saranno ignorati</item>
<item quantity="other">Eventi più vecchi di %d giorni saranno ignorati</item>
</plurals>
<string name="settings_sync_time_range_past_message">Eventi più vecchi di questo numero di giorni verranno ignorati(può anche essere 0). Lasciare in bianco per sincronizzare tutti gli eventi.</string>
<string name="settings_manage_calendar_colors">Cambia il colore del calendario</string>
<string name="settings_manage_calendar_colors_on">I colori dei calendari sono gestiti da DAVdroid</string>
<string name="settings_manage_calendar_colors_off">I colori dei calendari non sono gestiti da DAVdroid</string>
<string name="settings_event_colors">Supporto colore dell\'evento</string>
<string name="settings_event_colors_on">Sincronizza colori eventi</string>
<string name="settings_event_colors_off">Non sincronizza colori eventi</string>
<!--collection management-->
<string name="create_addressbook">Crea rubrica</string>
<string name="create_addressbook_display_name_hint">La mia rubrica</string>
<string name="create_calendar">Crea raccolta CalDAV</string>
<string name="create_calendar_display_name_hint">Mio calendario</string>
<string name="create_calendar_time_zone">Fuso orario:</string>
<string name="create_calendar_type">Tipo di raccolta:</string>
<string name="create_calendar_type_only_events">Calendario (solo eventi)</string>
<string name="create_calendar_type_only_tasks">Elenco attività (solo attività)</string>
<string name="create_calendar_type_events_and_tasks">Combinato (eventi e attività)</string>
<string name="create_collection_color">Imposta colore della raccolta</string>
<string name="create_collection_creating">Crea una raccolta</string>
<string name="create_collection_display_name">Mostra il nome (titolo) di questa raccolta:</string>
<string name="create_collection_display_name_required">Il titolo è richiesto</string>
<string name="create_collection_description">Descrizione (opzionale):</string>
<string name="create_collection_home_set">Imposta la home:</string>
<string name="create_collection_create">Crea</string>
<string name="delete_collection">Elimina raccolta</string>
<string name="delete_collection_confirm_title">Sei sicuro?</string>
<string name="delete_collection_confirm_warning">Questa raccolta (%s) e tutti i suoi dati saranno rimossi dal server.</string>
<string name="delete_collection_deleting_collection">Cancellazione della raccolta</string>
<string name="collection_force_read_only">Forza sola lettura</string>
<!--ExceptionInfoFragment-->
<string name="exception">Si è verificato un errore.</string>
<string name="exception_httpexception">Si è verificato un errore HTTP.</string>
<string name="exception_ioexception">Si è verificato un errore di I/O.</string>
<string name="exception_show_details">Mostra dettagli</string>
<!--sync adapters and DebugInfoActivity-->
<string name="debug_info_title">Informazioni di debug</string>
<string name="sync_contacts_read_only_address_book">Rubrica in sola lettura</string>
<string name="sync_error_permissions">Autorizzazioni DAVdroid</string>
<string name="sync_error_permissions_text">Autorizzazioni addizionali richieste</string>
<string name="sync_error_opentasks_too_old">OpenTasks troppo vecchia</string>
<string name="sync_error_opentasks_required_version">Versione richiesta: %1$s (attualmente %2$s)</string>
<string name="sync_error_authentication_failed">Autenticazione fallita (controlla credenziali login)</string>
<!--cert4android-->
<string name="certificate_notification_connection_security">DAVdroid: sicurezza della connessione</string>
<string name="trust_certificate_unknown_certificate_found">DAVdroid ha trovato un certificato sconosciuto. Ritenerlo affidabile?</string>
</resources>

View File

@@ -2,33 +2,46 @@
<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="notification_channel_debugging">デバッグ中</string>
<string name="notification_channel_general">他の重要なメッセージ</string>
<string name="notification_channel_sync">同期</string>
<string name="notification_channel_sync_errors">同期エラー</string>
<string name="notification_channel_sync_io_errors">ネットワークおよび I/O エラー</string>
<string name="notification_channel_sync_status">ステータスメッセージ</string>
<!--startup dialogs-->
<string name="startup_autostart_permission">自動同期</string>
<string name="startup_autostart_permission_message">%s ファームウェアは自動同期をブロックすることがよくあります。 この場合、Android の設定で自動同期を許可してください。</string>
<string name="startup_battery_optimization">スケジュール同期</string>
<string name="startup_battery_optimization_message">お使いのデバイスは DAVdroid の同期を制限します。 通常の DAVdroid 同期間隔を適用するには、「バッテリ最適化」をオフにしてください。</string>
<string name="startup_battery_optimization_disable">DAVdroid 用にオフにする</string>
<string name="startup_dont_show_again">次回から表示しない</string>
<string name="startup_development_version">DAVdroid プレビュー リリース</string>
<string name="startup_development_version_message">これは DAVdroid の開発版です。期待した通りに動作しない可能性があることにご注意ください。私たちが DAVdroid を改善するために、建設的なフィードバックをお願いします。</string>
<string name="startup_development_version_give_feedback">フィードバックする</string>
<string name="startup_not_now">後で</string>
<string name="startup_donate">オープンソース情報</string>
<string name="startup_donate_message">あなたがオープンソース ソフトウェア (GPLv3) の DAVdroid を使用していただくことに、私たちは満足しています。 DAVdroid の開発はハードワークで、何千もの作業時間がかかりました。寄付をご検討ください。</string>
<string name="startup_donate_now">寄付ページを表示</string>
<string name="startup_donate_later">たぶん後で</string>
<string name="startup_google_play_accounts_removed">Play ストア DRM バグ情報</string>
<string name="startup_google_play_accounts_removed_message">特定の条件下で、DAVdroid を再起動後またはアップグレードした後、Play ストア DRM によりすべての DAVdroid アカウントがなくなる可能性があります。この問題の影響を受けている場合 (のみ)、Play ストアから「DAVdroid JB 回避策」をインストールしてください。</string>
<string name="startup_google_play_accounts_removed_more_info">追加情報</string>
<string name="startup_more_info">追加情報</string>
<string name="startup_opentasks_not_installed">OpenTasks がインストールされていません</string>
<string name="startup_opentasks_not_installed_message">OpenTasks アプリが利用できないため、DAVdroid はタスクリストを同期することができません</string>
<string name="startup_opentasks_not_installed_message">タスクを同期するために、無料アプリのOpenTasksが必要です。 (連絡先/イベントには必要ありません)</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_libraries">ライブラリー</string>
<string name="about_version">バージョン %1s (%2d)</string>
<string name="about_build_date">コンパイル日時 %s</string>
<string name="about_flavor_info">このバージョンは Google Play での配信にのみ対応です。</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-->
@@ -36,14 +49,18 @@
<string name="navigation_drawer_close">ナビゲーションドロワーを閉じる</string>
<string name="navigation_drawer_subtitle">CalDAV/CardDAV 同期アダプター</string>
<string name="navigation_drawer_about">アプリについて / ライセンス</string>
<string name="navigation_drawer_beta_feedback">ベータフィードバック</string>
<string name="navigation_drawer_settings">設定</string>
<string name="navigation_drawer_news_updates">ニュース &amp; 更新</string>
<string name="navigation_drawer_external_links">外部リンク</string>
<string name="navigation_drawer_website">Web サイト</string>
<string name="navigation_drawer_manual">手動</string>
<string name="navigation_drawer_faq">FAQ</string>
<string name="navigation_drawer_forums">コミュニティ</string>
<string name="navigation_drawer_forums">ヘルプ / フォーラム</string>
<string name="navigation_drawer_donate">寄付</string>
<string name="account_list_empty">DAVdroid にようこそ!\n\nCalDAV/CardDAV アカウントを追加できるようになりました。</string>
<string name="accounts_global_sync_disabled">システム全体の自動同期が無効です</string>
<string name="accounts_global_sync_enable">有効</string>
<!--DavService-->
<string name="dav_service_refresh_failed">サービスの検出に失敗しました</string>
<string name="dav_service_refresh_couldnt_refresh">コレクション リストを更新できません</string>
@@ -53,12 +70,19 @@
<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_reset_trusted_certificates">信頼済証明書をリセット</string>
<string name="app_settings_reset_trusted_certificates_summary">以前承認されたすべての証明書を忘れます</string>
<plurals name="app_settings_reset_trusted_certificates_success">
<item quantity="other">%d 証明書の信頼を解除しました</item>
</plurals>
<string name="app_settings_distrust_system_certs">システム証明書の信頼を解除</string>
<string name="app_settings_distrust_system_certs_on">システムとユーザーが追加したCAを信頼しない</string>
<string name="app_settings_distrust_system_certs_off">システムとユーザーが追加したCAを信頼する (推奨)</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>
@@ -69,24 +93,26 @@
<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_select_collections_hint">同期するコレクションを選択</string>
<string name="account_carddav">CardDAV</string>
<string name="account_caldav">CalDAV</string>
<string name="account_webcal">Webcal</string>
<string name="account_synchronize_this_collection">このコレクションを同期</string>
<string name="account_read_only">読み取り専用</string>
<string name="account_calendar">カレンダー</string>
<string name="account_task_list">タスクリスト</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">ローカルの連絡先と CalDAV アドレス帳を同期するため、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>
<string name="account_no_webcal_handler_found">Webcal に対応するアプリが見つかりません</string>
<string name="account_install_icsdroid">ICSdroid をインストール</string>
<!--AddAccountActivity-->
<string name="login_title">アカウントを追加</string>
<string name="login_type_email">メールアドレスでログイン</string>
@@ -96,11 +122,13 @@
<string name="login_password_required">パスワードが必要です</string>
<string name="login_type_url">URL とユーザー名でログイン</string>
<string name="login_url_must_be_http_or_https">URL は http(s):// で始まる必要があります</string>
<string name="login_url_must_be_https">URL は https:// で始まる必要があります</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_auth_preemptive">プリエンプティブ認証 (推奨ですが、ダイジェスト認証と互換性がありません)</string>
<string name="login_type_url_certificate">URL とクライアント証明書でログイン</string>
<string name="login_select_certificate">証明書を選択</string>
<string name="login_login">ログイン</string>
<string name="login_back">戻る</string>
<string name="login_create_account">アカウントを作成</string>
@@ -112,7 +140,7 @@
<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>
<string name="login_view_logs">詳細を表示</string>
<!--AccountSettingsActivity-->
<string name="settings_title">設定: %s</string>
<string name="settings_authentication">認証</string>
@@ -121,31 +149,17 @@
<string name="settings_password">パスワード</string>
<string name="settings_password_summary">ご利用のサーバーに従ってパスワードを更新します。</string>
<string name="settings_enter_password">パスワードを入力:</string>
<string name="settings_preemptive">プリエンプティブ認証</string>
<string name="settings_preemptive_on">すべてのリクエストで資格情報を送信します (推奨)</string>
<string name="settings_preemptive_off">サーバーが要求した後、資格情報を送信します</string>
<string name="settings_certificate_alias">クライアント証明書の別名</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_summary_not_available">利用不可</string>
<string name="settings_sync_interval_calendars">カレンダー同期間隔</string>
<string name="settings_sync_interval_tasks">タスク同期間隔</string>
<string-array name="settings_sync_interval_seconds">
<item>-1</item>
<item>300</item>
<item>600</item>
<item>900</item>
<item>3600</item>
<item>7200</item>
<item>14400</item>
<item>86400</item>
</string-array>
<string-array name="settings_sync_interval_names">
<item>手動のみ</item>
<item>5 分ごと</item>
<item>10 分ごと</item>
<item>15 分ごと</item>
<item>30 分ごと</item>
<item>1 時間ごと</item>
<item>2 時間ごと</item>
<item>4 時間ごと</item>
@@ -154,10 +168,10 @@
<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_sync_wifi_only_ssid">WiFi SSID 制限</string>
<string name="settings_sync_wifi_only_ssid_on">%s でのみ同期します</string>
<string name="settings_sync_wifi_only_ssid_off">すべての WiFi 接続使用することができます</string>
<string name="settings_sync_wifi_only_ssid_message">このネットワークで同期を制限する WiFi ネットワーク (SSID) の名前を入力してください。すべての WiFi 接続は空白のままにします。</string>
<string name="settings_sync_wifi_only_ssids">WiFi SSID 制限</string>
<string name="settings_sync_wifi_only_ssids_on">%s でのみ同期します</string>
<string name="settings_sync_wifi_only_ssids_off">すべての WiFi 接続使用されます</string>
<string name="settings_sync_wifi_only_ssids_message">利用可能な WiFi ネットワークのカンマ区切りの名前 (SSID) (空白にするとすべて)</string>
<string name="settings_carddav">CardDAV</string>
<string name="settings_contact_group_method">連絡先グループ方法</string>
<string-array name="settings_contact_group_method_values">
@@ -168,9 +182,8 @@
<item>グループは個別の VCards</item>
<item>グループは連絡先カテゴリーごと</item>
</string-array>
<string name="settings_rfc6868_for_vcards">RFC6868 の VCards を使用する</string>
<string name="settings_rfc6868_for_vcards_on">二重引用符を、パラメーター値に使用することができます</string>
<string name="settings_rfc6868_for_vcards_off">二重引用符を、パラメーター値に使用することができません</string>
<string name="settings_contact_group_method_change">グループ方法を変更</string>
<string name="settings_contact_group_method_change_reload_contacts">これはすべての連絡先を再読み込みする必要があります。 保存していないローカルの変更は破棄されます。</string>
<string name="settings_caldav">CalDAV</string>
<string name="settings_sync_time_range_past">過去イベントの時間限度</string>
<string name="settings_sync_time_range_past_none">すべてのイベントが同期されます</string>
@@ -181,9 +194,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_version_update">DAVdroid バージョンの更新</string>
<string name="settings_version_update_settings_updated">内部設定が更新されました。</string>
<string name="settings_version_update_install_hint">問題がありますか? 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>
@@ -205,34 +219,32 @@
<string name="delete_collection_confirm_title">よろしいですか?</string>
<string name="delete_collection_confirm_warning">このコレクション (%s) とそのすべてのデータがサーバーから削除されます。</string>
<string name="delete_collection_deleting_collection">コレクションの削除中</string>
<string name="collection_force_read_only">強制的に読み取り専用</string>
<string name="collection_properties">プロパティ</string>
<string name="collection_properties_url">アドレス (URL):</string>
<string name="collection_properties_copy_url">URL をコピー</string>
<!--ExceptionInfoFragment-->
<string name="exception">エラーが発生しました。</string>
<string name="exception_httpexception">HTTP エラーが発生しました。</string>
<string name="exception_ioexception">I/O エラーが発生しました。</string>
<string name="exception_show_details">詳細を表示</string>
<!--sync errors and DebugInfoActivity-->
<!--sync adapters and DebugInfoActivity-->
<string name="debug_info_title">デバッグ情報</string>
<string name="sync_contacts_read_only_address_book">読み取り専用のアドレス帳</string>
<plurals name="sync_contacts_local_contact_changes_discarded">
<item quantity="other">%d ローカル連絡先の変更が破棄されました</item>
</plurals>
<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>
<string name="sync_error_opentasks_too_old">OpenTasks が古すぎます</string>
<string name="sync_error_opentasks_required_version">必要なバージョン: %1$s (現在 %2$s)</string>
<string name="sync_error_authentication_failed">認証に失敗しました (ログイン情報を確認してください)</string>
<string name="sync_error_io">ネットワークまたは I/O エラー %s</string>
<string name="sync_error_http_dav">HTTP サーバーエラー %s</string>
<string name="sync_error_local_storage">内蔵ストレージエラー %s</string>
<string name="sync_error_retry">再試行</string>
<string name="sync_error_view_item">アイテムを表示</string>
<!--cert4android-->
<string name="certificate_notification_connection_security">DAVdroid: 接続セキュリティ</string>
<string name="trust_certificate_unknown_certificate_found">DAVdroidは、未知の証明書を検出しました。それを信頼しますか?</string>
</resources>

View File

@@ -0,0 +1,217 @@
<?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_disable">Skru av for DAVdroid</string>
<string name="startup_dont_show_again">Ikke vis igjen</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">DRM-feilinformasjon på Play-butikken</string>
<string name="startup_google_play_accounts_removed_message">Under gitte forhold vil DRM fra Play-butikken forårsake at alle DAVdroid-kontoer forsvinner etter omstart eller etter oppgradering av DAVdroid. Hvis du rammes av dette problemet (og bare da), installer \"DAVdroid JB Workaround\" fra Play-butikken.</string>
<string name="startup_opentasks_not_installed">OpenTasks er ikke installert</string>
<string name="startup_opentasks_reinstall_davdroid">Etter å ha installert OpenTasks, må du reinstallere Davdroid og legge til kontoene dine igjen (Android-feil).</string>
<string name="startup_opentasks_not_installed_install">Installer OpenTasks</string>
<!--AboutActivity-->
<string name="about_license_info_no_warranty">Dette programmet kommer uten NOEN FORM FOR GARANTI. Det er fri programvare, og du er velkommen til å redistribuere det under gitte forhold.</string>
<!--global settings-->
<string name="logging_davdroid_file_logging">DAVDroid fil-logging</string>
<string name="logging_to_external_storage">Logger til ekstern lagringsmedium: %s</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_subtitle">CalDAV/CardDAV -synkroniseringsadapter</string>
<string name="navigation_drawer_about">Om / Lisens</string>
<string name="navigation_drawer_beta_feedback">Tilbakemelding om beta-en</string>
<string name="navigation_drawer_settings">Innstillinger</string>
<string name="navigation_drawer_news_updates">Nyheter og oppdateringer</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="account_list_empty">Velkommen til DAVdroid.\n\nDu kan legge til en CalDAV/CardDAV-konto nå.</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_distrust_system_certs_on">System og brukertillagte sertifikatsmyntigheter vil ikke bli tiltrodd</string>
<string name="app_settings_distrust_system_certs_off">System- og bruker -tillagte sertifikatsmyndigheter vil bli tiltrodd (anbefalt)</string>
<string name="app_settings_reset_certificates">Tilbakestill (ikke)tiltrodde sertifikater</string>
<string name="app_settings_reset_certificates_summary">Tilbakestiller tillit til alle egendefinerte sertifikater</string>
<string name="app_settings_reset_certificates_success">Alle egendefinerte sertifikater har blitt fjernet</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_log_to_external_storage_off">Ekstern fillogging har blitt skrudd av</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_new_name">Ulagret lokal data kan bli avslått. Ny synkronisering kreves etter ny navngivning. Nytt kontonavn:</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_delete_confirmation_text">Alle lokale kopier av adressebøker, kalendere og gjøremålslister vil bli slettet.</string>
<string name="account_carddav">CardDAV</string>
<string name="account_caldav">CalDAV</string>
<string name="account_webcal">Webcal</string>
<string name="account_synchronize_this_collection">synkroniser denne samlingen</string>
<string name="account_read_only">kun lesbar</string>
<string name="account_calendar">kalender</string>
<string name="account_task_list">oppgaveliste</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>
<string name="account_no_webcal_handler_found">Fant ingen programmer med støtte for Webcal</string>
<string name="account_install_icsdroid">Installer ICSdroid</string>
<!--AddAccountActivity-->
<string name="login_title">Legg til konto</string>
<string name="login_type_email">Innlogging med e-postadresse</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_type_url">Logg inn med nettadresse og brukernavn</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_user_name">Brukernavn</string>
<string name="login_user_name_required">Brukernavn påkrevd</string>
<string name="login_base_url">Landings-nettadresse</string>
<string name="login_login">Logg inn</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_info">Bruk din e-postadresse som kontonavn fordi Android vil bruke kontonavnet som ORGANISATOR-felt for hendelser du oppretter. Du kan ikke ha to kontoer med samme navn.</string>
<string name="login_account_contact_group_method">Kontaktgruppemetode:</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>
<!--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_summary_periodically" tools:ignore="PluralsCandidate">Hvert %d minutt + umiddelbart ved lokale endringer</string>
<string name="settings_sync_interval_calendars">Kalendersynkroniseringsintervall</string>
<string name="settings_sync_interval_tasks">Gjøremålssynkroniseringsintervall</string>
<string-array name="settings_sync_interval_names">
<item>Bare manuelt</item>
<item>Hvert kvarter</item>
<item>Hver halvtime</item>
<item>Hver time</item>
<item>Hver andre time</item>
<item>Hver fjerde time</item>
<item>Én gang om dagen</item>
</string-array>
<string name="settings_sync_wifi_only">Bare synk. over Wi-Fi</string>
<string name="settings_sync_wifi_only_on">Synkronisering er begrenset til Wi-Fi -tilkoblinger</string>
<string name="settings_sync_wifi_only_off">Tilkoblingstypen blir ikke tatt i betraktning</string>
<string name="settings_sync_wifi_only_ssids">Wi-Fi SSID -begrensning</string>
<string name="settings_sync_wifi_only_ssids_on">Vil kun synkronisere over %s</string>
<string name="settings_sync_wifi_only_ssids_off">Alle Wi-Fi -tilkoblinger vil bli brukt</string>
<string name="settings_sync_wifi_only_ssids_message">Kommainndelte navn (SSID-er) på tillatte Wi-Fi -nettverk (la stå tomt for alle)</string>
<string name="settings_carddav">CardDAV</string>
<string name="settings_contact_group_method">Kontaktgruppemetode</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>Grupper er egne vKort</item>
<item>Grupper er kategorier per kontakt</item>
</string-array>
<string name="settings_contact_group_method_change">Endre gruppemetode</string>
<string name="settings_contact_group_method_change_reload_contacts">Dette krever ny innlasting av alle kontakter. Ulagrede lokale endringer vil bli forkastet.</string>
<string name="settings_caldav">CalDAV</string>
<string name="settings_sync_time_range_past">Tidsgrense for tidligere hendelser</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_sync_time_range_past_message">Hendelser som er mer enn dette antallet dager i fortid vil bli ignorert (kan være 0). La stå tomt for å synkronisere alle hendelser.</string>
<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>
<string name="settings_event_colors">Støtte for fargelegging av hendelser</string>
<string name="settings_event_colors_on">Synkroniser hendelsesfarger</string>
<string name="settings_event_colors_off">Ikke synkroniser hendelsesfarger</string>
<string name="settings_event_colors_off_confirm">Det kan hende at det å skru av hendelsesfarger vil fjerne allerede synkroniserte hendelsesfarger.</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_home_set">Hjemmemappe:</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_confirm_warning">Denne samlingen (%s) og all dens data vil bli fjernet fra tjeneren.</string>
<string name="delete_collection_deleting_collection">Sletter samling</string>
<string name="collection_force_read_only">Tving kun lesbar</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 adapters and DebugInfoActivity-->
<string name="debug_info_title">Feilrettingsinfo</string>
<string name="sync_contacts_read_only_address_book">Adressebok uten skrivetilgang</string>
<plurals name="sync_contacts_local_contact_changes_discarded">
<item quantity="one">Lokal kontaktendring forkastet</item>
<item quantity="other">%d lokale kontaktendringer forkastet</item>
</plurals>
<string name="sync_error_permissions">DAVdroid-tilganger</string>
<string name="sync_error_permissions_text">Ytterligere tilganger kreves</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>

View File

@@ -2,33 +2,29 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!--common strings-->
<string name="app_name">DAVdroid</string>
<string name="account_title_address_book">DAVdroid Adresboek</string>
<string name="address_books_authority_title">Adresboeken</string>
<string name="help">Help</string>
<string name="manage_accounts">Beheer accounts</string>
<string name="please_wait">Een moment geduld...</string>
<string name="please_wait">Een moment geduld</string>
<string name="send">Verzenden</string>
<!--startup dialogs-->
<string name="startup_battery_optimization_disable">DAVdroid afsluiten</string>
<string name="startup_dont_show_again">Niet opnieuw weergeven</string>
<string name="startup_development_version">DAVdroid voorlopige versie</string>
<string name="startup_development_version_message">Dit is een ontwikkelversie van DAVdroid. Het kan zijn dat dingen niet werken zoals verwacht. Geef ons constructieve feedback om DAVdroid te verbeteren.</string>
<string name="startup_development_version_give_feedback">Feedback geven</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>
<string name="startup_donate_later">Misschien later</string>
<string name="startup_google_play_accounts_removed">Play Store DRM fout-informatie</string>
<string name="startup_google_play_accounts_removed_message">Onder bepaalde omstandigheden, kan Play Store DRM ervoor zorgen dat accounts kwijt zijn na een herstart of na een DAVdroid update. Als dit probleem zich bij je voordoet (en alleen dan), Installeer dan \"DAVdroid JB Workaround\" vanuit de Play Store</string>
<string name="startup_google_play_accounts_removed_more_info">Meer informatie</string>
<string name="startup_opentasks_not_installed">OpenTasks niet geinstalleerd</string>
<string name="startup_opentasks_not_installed_message">De OpenTasks app is niet beschikbaar, Hierdoor is het voor DAVdroid niet mogelijk om uw taken te synchroniseren.</string>
<string name="startup_opentasks_reinstall_davdroid">Na installatie van OpenTasks dient u DAVdroid opnieuw te installeren en de accounts toe te voegen (Android bug).</string>
<string name="startup_opentasks_not_installed_install">OpenTasks installeren</string>
<!--AboutActivity-->
<string name="about_license_terms">Licentie voorwaarden</string>
<string name="about_license_info_no_warranty">Dit programma kom met ABSOLUUT GEEN GARANTIE. Het is gratis software, en je bent welkom dit te herdistribueren onder bepaalde voorwaarden.</string>
<!--global settings-->
<string name="logging_davdroid_file_logging">DAVDroid bestand loggen</string>
<string name="logging_to_external_storage">Loggen naar externe opslag: %s</string>
<string name="logging_to_external_storage_warning">Verwijder logs zo snel mogelijk</string>
<string name="logging_couldnt_create_file">Kon extern log bestand niet verwijderen: %s</string>
<string name="logging_no_external_storage">Externe opslag niet gevonden</string>
<!--AccountsActivity-->
@@ -36,14 +32,17 @@
<string name="navigation_drawer_close">Sluit navigatie drawer</string>
<string name="navigation_drawer_subtitle">CalDAV/CardDav Sync adapter</string>
<string name="navigation_drawer_about">Over / Licentie</string>
<string name="navigation_drawer_beta_feedback">Beta terugkoppeling</string>
<string name="navigation_drawer_settings">Instellingen</string>
<string name="navigation_drawer_news_updates">Nieuws &amp; updates</string>
<string name="navigation_drawer_external_links">Externe links</string>
<string name="navigation_drawer_website">Website</string>
<string name="navigation_drawer_faq">FAQ</string>
<string name="navigation_drawer_forums">Community</string>
<string name="navigation_drawer_forums">Help / Forums</string>
<string name="navigation_drawer_donate">Doneren</string>
<string name="account_list_empty">Welkom bij DAVdroid!\n\nJe kunt nu een CalDAV/CardDAv account toevoegen.</string>
<string name="accounts_global_sync_disabled">Systeembrede automatische synchronisatie is uitgeschakeld</string>
<string name="accounts_global_sync_enable">Inschakelen</string>
<!--DavService-->
<string name="dav_service_refresh_failed">Service herkenning is mislukt</string>
<string name="dav_service_refresh_couldnt_refresh">Kon de collectie lijst niet vernieuwen</string>
@@ -53,13 +52,19 @@
<string name="app_settings_reset_hints">Hints resetten </string>
<string name="app_settings_reset_hints_summary">Hints die al gezien zijn opnieuw weergeven</string>
<string name="app_settings_reset_hints_success">Alle hints worden opnieuw weergegeven</string>
<string name="app_settings_connection">Verbinding</string>
<string name="app_settings_override_proxy">Proxy instellingen overschrijven</string>
<string name="app_settings_override_proxy_on">Eigen proxy instellingen gebruiken</string>
<string name="app_settings_override_proxy_off">Systeem proxy instellingen gebruiken</string>
<string name="app_settings_override_proxy_host">HTTP proxy beheerder naam</string>
<string name="app_settings_override_proxy_port">HTTP proxy poort</string>
<string name="app_settings_security">Beveiliging</string>
<string name="app_settings_reset_trusted_certificates">Vertrouwde certificaten resetten</string>
<string name="app_settings_reset_trusted_certificates_summary">Vergeet alle eerder geaccepteerde certificaten</string>
<plurals name="app_settings_reset_trusted_certificates_success">
<item quantity="one">Onbetrouwbaar certificaat</item>
<item quantity="other">Onbetrouwbaar %d certificaten</item>
</plurals>
<string name="app_settings_distrust_system_certs">Systeem certificaten niet vertrouwen</string>
<string name="app_settings_distrust_system_certs_on">Systeem en CAs van toegevoegde gebruiker wordt niet vertrouwd</string>
<string name="app_settings_distrust_system_certs_off">Systeem en CAs van toegevoegde gebruiker wordt vertrouwd (aanbevolen)</string>
<string name="app_settings_reset_certificates">Resetten (niet) vertrouwde certificaten</string>
<string name="app_settings_reset_certificates_summary">Resetten alle bewerkte certificaten</string>
<string name="app_settings_reset_certificates_success">Alle bewerkte certificaten zijn vrijgemaakt</string>
<string name="app_settings_debug">Debuggen</string>
<string name="app_settings_log_to_external_storage">Log naar extern bestand</string>
<string name="app_settings_log_to_external_storage_on">Loggen naar externe opslag (wanneer beschikbaar)</string>
@@ -68,26 +73,23 @@
<string name="app_settings_show_debug_info_details">Bekijk/deel software configuratie details</string>
<!--AccountActivity-->
<string name="account_synchronize_now">Synchroniseer nu</string>
<string name="account_synchronizing_now">Aan het synchronizeren...</string>
<string name="account_synchronizing_now">Aan het synchronizeren</string>
<string name="account_settings">Account instellingen</string>
<string name="account_rename">Account hernoemen</string>
<string name="account_rename_new_name">Niet opgeslagen lokale informatie mag verloren gaan. Synchronisatie is noodzakelijk na hernoemen. Nieuw account naam:</string>
<string name="account_rename_rename">Hernoemen</string>
<string name="account_delete">Account verwijderen</string>
<string name="account_delete_confirmation_title">Account echt verwijderen?</string>
<string name="account_delete_confirmation_text">Alle lokale kopieën van adresboeken, agenda\'s en taken worden verwijderd.</string>
<string name="account_carddav">CardDAV</string>
<string name="account_caldav">CalDAV</string>
<string name="account_webcal">Webcal</string>
<string name="account_refresh_address_book_list">Adresboeken vernieuwen</string>
<string name="account_create_new_address_book">Maak een nieuw adresboek</string>
<string name="account_refresh_calendar_list">Agenda\'s vernieuwen</string>
<string name="account_create_new_calendar">Maak een nieuwe agenda</string>
<!--PermissionsActivity-->
<string name="permissions_title">DAVdroid rechten</string>
<string name="permissions_calendar">Agenda rechten</string>
<string name="permissions_calendar_details">Om CalDAV afspraken te synchroniseren met u agenda dient DAVdroid toegang te verkrijgen. </string>
<string name="permissions_calendar_request">Agenda rechten verkrijgen</string>
<string name="permissions_contacts">Contact rechten</string>
<string name="permissions_contacts_details">Om CalDAV afspraken te synchroniseren met u contacten dient DAVdroid toegang te verkrijgen. </string>
<string name="permissions_contacts_request">Contacten rechten verkrijgen</string>
<string name="permissions_opentasks">OpenTasks rechten</string>
<string name="permissions_opentasks_details">Om CalDAV taken te synchroniseren met uw local takenlijst dient DAVdroid toegang te hebben tot OpenTasks</string>
<string name="permissions_opentasks_request">OpenTasks rechten verkrijgen</string>
<string name="account_no_webcal_handler_found">Geen mogelijke Webcal app gevonden</string>
<string name="account_install_icsdroid">ICSdroid installeren</string>
<!--AddAccountActivity-->
<string name="login_title">Account toevoegen</string>
<string name="login_type_email">Inloggen met e-mailadres</string>
@@ -101,18 +103,17 @@
<string name="login_user_name">Gebruikersnaam</string>
<string name="login_user_name_required">Gebruikersnaam vereist</string>
<string name="login_base_url">Basis URL</string>
<string name="login_auth_preemptive">Preëmptieve authenticatie (aanbevolen, maar werkt niet met Digest-auth)</string>
<string name="login_login">Login</string>
<string name="login_back">Terug</string>
<string name="login_create_account">Maak een account</string>
<string name="login_account_name">Accountnaam</string>
<string name="login_account_name_info">Gebruik je email adres als account naam want Android zal je account naam gebruiken als ORGANIZER veld voor gemaakte afspraken. Je kunt geen 2 accounts met dezelfde naam hebben,</string>
<string name="login_account_contact_group_method">Contact groep methode:</string>
<string name="login_account_name_required">Accountnaam vereist</string>
<string name="login_account_not_created">Account kon niet gemaakt worden.</string>
<string name="login_configuration_detection">Configuratie detectie</string>
<string name="login_querying_server">Even geduld, verzoek naar server...</string>
<string name="login_querying_server">Even geduld, verzoek naar server</string>
<string name="login_no_caldav_carddav">Kon geen CalDAV of CardDAV service vinden.</string>
<string name="login_view_logs">Bekijk logs</string>
<!--AccountSettingsActivity-->
<string name="settings_title">Instellingen: %s</string>
<string name="settings_authentication">Authenticatie</string>
@@ -121,43 +122,28 @@
<string name="settings_password">Wachtwoord</string>
<string name="settings_password_summary">Gebruik het zelfde wachtwoord als op de server.</string>
<string name="settings_enter_password">Wachtwoord invoeren:</string>
<string name="settings_preemptive">Preëmptieve authenticatie</string>
<string name="settings_preemptive_on">Credentials worden met elk verzoek verzonden (aanbevolen)</string>
<string name="settings_preemptive_off">Credentials worden alleen op aanvraag verzonden</string>
<string name="settings_sync">Synchronisatie</string>
<string name="settings_sync_interval_contacts">Contacten verversen</string>
<string name="settings_sync_summary_manually">Alleen handmatig</string>
<string name="settings_sync_summary_periodically" tools:ignore="PluralsCandidate">Elke %d minuten + meteen na wijziging</string>
<string name="settings_sync_summary_not_available">Niet beschikbaar</string>
<string name="settings_sync_interval_calendars">Agenda\'s verversen</string>
<string name="settings_sync_interval_tasks">Taak sync. tussentijd</string>
<string-array name="settings_sync_interval_seconds">
<item>-1</item>
<item>300</item>
<item>600</item>
<item>900</item>
<item>3600</item>
<item>7200</item>
<item>14400</item>
<item>86400</item>
</string-array>
<string-array name="settings_sync_interval_names">
<item>Alleen handmatig</item>
<item>Elke 5 minuten</item>
<item>Elke 10 minuten</item>
<item>Elke 15 minuten</item>
<item>Elk uur</item>
<item>Elke 2 uur</item>
<item>Elke 4 uur</item>
<item>Dagelijks</item>
</string-array>
<string name="settings_sync_wifi_only">Sync alleen tijdens WiFi</string>
<string name="settings_sync_wifi_only_on">Synchronisatie is voorbehouden tijdens WiFi verbindingen</string>
<string name="settings_sync_wifi_only_off">Verbinding type is niet overwogen</string>
<string name="settings_sync_wifi_only_ssid">WiFi SSID beperking</string>
<string name="settings_sync_wifi_only_ssid_on">Zal alleen synchroniseren over %s</string>
<string name="settings_sync_wifi_only_ssid_off">Alle WiFI verbindingen mogen worden gebruikt</string>
<string name="settings_sync_wifi_only_ssid_message">Type de naam van het WiFi netwerk (SSID) om synchronisatie tot dit netwerk te beperken. Leeg laten voor sync over alle netwerken.</string>
<string name="settings_sync_wifi_only_ssids">WiFi SSID beperking</string>
<string name="settings_sync_wifi_only_ssids_on">Zal alleen synchroniseren over %s</string>
<string name="settings_sync_wifi_only_ssids_off">Alle WiFI verbindingen zullen worden gebruikt</string>
<string name="settings_carddav">CardDAV</string>
<string name="settings_contact_group_method">Contact groep methode</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>Groepen zijn apparte VCards</item>
<item>Groepen zijn per-contact categories</item>
</string-array>
<string name="settings_caldav">CalDAV</string>
<string name="settings_sync_time_range_past">Tijdslimiet verleden afspraken</string>
<string name="settings_sync_time_range_past_none">Alle afspraken worden gesynchronizeerd</string>
@@ -169,9 +155,9 @@
<string name="settings_manage_calendar_colors">Agenda kleuren beheren</string>
<string name="settings_manage_calendar_colors_on">Agenda kleuren worden door DAVdroid beheerd.</string>
<string name="settings_manage_calendar_colors_off">Agenda kleuren worden niet door DAVdroid ingesteld</string>
<string name="settings_version_update">DAVdroid versie update</string>
<string name="settings_version_update_settings_updated">Interne instellingen zijn bijgewerkt.</string>
<string name="settings_version_update_install_hint">Problemen? Deïnstalleer DAVdroid, daarna herinstalleren.</string>
<string name="settings_event_colors">Evenement kleur ondersteuning</string>
<string name="settings_event_colors_on">Evenement kleuren synchroniseren</string>
<string name="settings_event_colors_off">Evenement kleuren niet synchroniseren</string>
<!--collection management-->
<string name="create_addressbook">Maak adresboek</string>
<string name="create_addressbook_display_name_hint">Mijn adresboek</string>
@@ -198,15 +184,12 @@
<string name="exception_httpexception">Er is een HTTP fout opgetreden.</string>
<string name="exception_ioexception">Er is een I/O fout opgetreden.</string>
<string name="exception_show_details">Toon details</string>
<!--sync errors and DebugInfoActivity-->
<!--sync adapters and DebugInfoActivity-->
<string name="debug_info_title">Debug informatie</string>
<string name="sync_contacts_read_only_address_book">Alleen-lezen adresboek</string>
<string name="sync_error_permissions">DAVdroid rechten</string>
<string name="sync_error_permissions_text">Aanvullende rechten vereist</string>
<string name="sync_error_calendar">Agenda synchronisatie is mislukt (%s)</string>
<string name="sync_error_contacts">Adresboek synchronisatie is mislukt (%s)</string>
<string name="sync_error_tasks">Taak synchronisatie is mislukt (%s)</string>
<string name="sync_error">Fout tijdens %s</string>
<string name="sync_error_http_dav">Serverfout tijdens %s</string>
<string name="sync_error_local_storage">Database fout tijdens %s</string>
<string name="sync_error_unauthorized">Gebruikersnaam/wachtwoord onjuist</string>
<!--cert4android-->
<string name="certificate_notification_connection_security">DAVdroid: Verbinding beveiliging</string>
<string name="trust_certificate_unknown_certificate_found">Davdroid is benaderd door een onbekend certificaat. Vertrouwd u dit?</string>
</resources>

View File

@@ -0,0 +1,225 @@
<?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">Książka adresowa DAVdroid</string>
<string name="address_books_authority_title">Książka adresowa</string>
<string name="help">Pomoc</string>
<string name="manage_accounts">Zadządzaj kontami</string>
<string name="please_wait">Proszę czekać</string>
<string name="send">Wyślij</string>
<string name="notification_channel_debugging">Debugowanie</string>
<!--startup dialogs-->
<string name="startup_battery_optimization_disable">Wyłącz dla DAVdroid</string>
<string name="startup_dont_show_again">Nie pokazuj ponownie</string>
<string name="startup_donate">Informacje Open-Source</string>
<string name="startup_donate_message">Jesteśmy szczęśliwi, że używasz DAVdroid, który jest oprogramowaniem open-source (GPLv3). Ponieważ rozwijanie DAVdroid jest ciężką pracą i zajęło nam tysiące godzin pracy, prosimy o rozważenie darowizny.</string>
<string name="startup_donate_now">Pokaż stronę darowizny</string>
<string name="startup_donate_later">Może później</string>
<string name="startup_google_play_accounts_removed">Informacje o błędzie DRM Sklepu Play</string>
<string name="startup_google_play_accounts_removed_message">Pod pewnymi warunkami, DRM Sklepu Play może powodować, że wszystkie konta DAVdroid mogą zostać usunięte po uruchomieniu lub po uaktualnieniu DAVdroid. Jeśli jesteś dotknięty tym problemem (i tylko wtedy) należy zainstalować \"DAVdroid JB Obejście\" ze Sklepu Play.</string>
<string name="startup_opentasks_not_installed">OpenTasks nie jest zainstalowany</string>
<string name="startup_opentasks_reinstall_davdroid">Po zainstalowaniu OpenTasks konieczne jest PRZEINSTALOWANIE DAVdroid i ponowne dodanie twoich kont (błąd Androida).</string>
<string name="startup_opentasks_not_installed_install">Zainstaluj OpenTasks</string>
<!--AboutActivity-->
<string name="about_license_info_no_warranty">Ten program jest ABSOLUTNIE BEZ GWARANCJI. To jest wolne oprogramowanie i mile widziane jest dalsze rozpowszechnianie go pod pewnymi warunkami.</string>
<!--global settings-->
<string name="logging_davdroid_file_logging">Plik logów DAVdroid</string>
<string name="logging_to_external_storage">Logowanie do zewnątrznej pamięci: %s</string>
<string name="logging_couldnt_create_file">Nie można stworzyć zewnętrznego pliku logów: %s</string>
<string name="logging_no_external_storage">Zewnętrzna pamięci nie została naleziona</string>
<!--AccountsActivity-->
<string name="navigation_drawer_open">Otwórz menu nawigacji</string>
<string name="navigation_drawer_close">Zamknij menu nawigacji</string>
<string name="navigation_drawer_subtitle">Adapter synchronizacji CalDAV/CardDAV</string>
<string name="navigation_drawer_about">O DAVdroid / Licencja</string>
<string name="navigation_drawer_beta_feedback">Przekaż opinię</string>
<string name="navigation_drawer_settings">Ustawienia</string>
<string name="navigation_drawer_news_updates">Nowości &amp; aktualizacje</string>
<string name="navigation_drawer_external_links">Zewnętrzne odnośniki</string>
<string name="navigation_drawer_website">Strona WWW</string>
<string name="navigation_drawer_manual">Ręcznie</string>
<string name="navigation_drawer_faq">Pytania i odpowiedzi</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>
<string name="accounts_global_sync_enable">Włącz</string>
<!--DavService-->
<string name="dav_service_refresh_failed">Wykrycie serwisu nie powiodło się</string>
<string name="dav_service_refresh_couldnt_refresh">Nie można odświeżyć listy kolekcji</string>
<!--AppSettingsActivity-->
<string name="app_settings">Ustawienia</string>
<string name="app_settings_user_interface">Interfejs użytkownika</string>
<string name="app_settings_reset_hints">Zresetuj podpowiedzi</string>
<string name="app_settings_reset_hints_summary">Ponownie włącz wskazówki, które zostały usunięte wcześniej</string>
<string name="app_settings_reset_hints_success">Wszystkie wskazówki pojawią się ponownie</string>
<string name="app_settings_connection">Łączność</string>
<string name="app_settings_override_proxy">Nadpisz ustawienia proxy</string>
<string name="app_settings_override_proxy_on">Użyj niestandardowych ustawień proxy </string>
<string name="app_settings_override_proxy_off">Użyj systemowych ustawień proxy</string>
<string name="app_settings_override_proxy_host">Nazwa hosta proxy HTTP</string>
<string name="app_settings_override_proxy_port">Port proxy HTTP</string>
<string name="app_settings_security">Bezpieczeństwo</string>
<string name="app_settings_distrust_system_certs">Usuń certyfikaty systemowe</string>
<string name="app_settings_distrust_system_certs_on">CA systemowe i użytkownika nie zostaną dodane</string>
<string name="app_settings_distrust_system_certs_off">CA systemowe i użytkownika zostaną dodane (zalecane)</string>
<string name="app_settings_reset_certificates">Zresetuj (nie)zaufane certyfikaty</string>
<string name="app_settings_reset_certificates_summary">Zresetuj wszystkie niestandardowe certyfikaty.</string>
<string name="app_settings_reset_certificates_success">Wszystkie niestandardowe certyfikaty zostały wyczyszczone</string>
<string name="app_settings_debug">Debugowanie</string>
<string name="app_settings_log_to_external_storage">Loguj do zewnętrznego pliku</string>
<string name="app_settings_log_to_external_storage_on">Logowanie do zewnętrznej pamięci (jeśli jest dostępna)</string>
<string name="app_settings_log_to_external_storage_off">Logowanie do zewnętrznego pliku jest wyłączone</string>
<string name="app_settings_show_debug_info">Pokaż informacje do debugowania</string>
<string name="app_settings_show_debug_info_details">Przejrzyj lub udostępnij informacje o programie i jego konfiguracji</string>
<!--AccountActivity-->
<string name="account_synchronize_now">Synchronizuj teraz</string>
<string name="account_synchronizing_now">Synchronizcja w toku</string>
<string name="account_settings">Ustawienia konta</string>
<string name="account_rename">Zmień nazwę konta</string>
<string name="account_rename_new_name">Niezapisane dane lokalne mogą zostać usunięte. Ponowna synchronizacja jest wymagana po zmianie nazwy. Nowa nazwa konta:</string>
<string name="account_rename_rename">Zmień nazwę</string>
<string name="account_delete">Usuń konto</string>
<string name="account_delete_confirmation_title">Naprawdę chcesz usunąć konto?</string>
<string name="account_delete_confirmation_text">Wszystkie lokalne kopie książek adresowych, kalendarzy i list zadań zostaną usunięte.</string>
<string name="account_carddav">CardDAV</string>
<string name="account_caldav">CalDAV</string>
<string name="account_webcal">Webcal</string>
<string name="account_synchronize_this_collection">Synchronizuj kolekcję</string>
<string name="account_read_only">tylko do odczytu</string>
<string name="account_calendar">kalendarz</string>
<string name="account_task_list">lista zadań</string>
<string name="account_refresh_address_book_list">Odśwież listę książek adresowych</string>
<string name="account_create_new_address_book">Stwórz nową książkę adresową</string>
<string name="account_refresh_calendar_list">Odśwież listę kalendarzy</string>
<string name="account_create_new_calendar">Stwórz nowy kalendarz</string>
<string name="account_no_webcal_handler_found">Nie znaleziono aplikacji obsługującej Webcal</string>
<string name="account_install_icsdroid">Zainstaluj ICSdroid</string>
<!--AddAccountActivity-->
<string name="login_title">Dodaj konto</string>
<string name="login_type_email">Logowanie za pomocą adresu e-mail</string>
<string name="login_email_address">Adres e-mail</string>
<string name="login_email_address_error">Wymagany poprawny adres e-mail</string>
<string name="login_password">Hasło</string>
<string name="login_password_required">Wymagane hasło</string>
<string name="login_type_url">Logowanie za pomocą adresu URL i nazwy użytkownika</string>
<string name="login_url_must_be_http_or_https">URL musi zaczynać się od http(s)://</string>
<string name="login_url_must_be_https">Adres URL musi zaczynać się od https://</string>
<string name="login_url_host_name_required">Wymagana nazwa hosta</string>
<string name="login_user_name">Nazwa użytkownika</string>
<string name="login_user_name_required">Wymagana nazwa użytkownika</string>
<string name="login_base_url">Podstawowy URL</string>
<string name="login_type_url_certificate">Logowanie za pomocą adresu URL i certyfikatu klienta</string>
<string name="login_select_certificate">Wybierz certyfikat</string>
<string name="login_login">Zaloguj</string>
<string name="login_back">Wróć</string>
<string name="login_create_account">Stwórz konto</string>
<string name="login_account_name">Nazwa konta</string>
<string name="login_account_name_info">Użyj swojego adresu e-mail jako nazwy konta, ponieważ Android będzie używał nazwy konta jako pola ORGANIZATOR dla wydarzeń, które stworzysz. Nie możesz posiadać dwóch kont o takiej samej nazwie.</string>
<string name="login_account_contact_group_method">Metoda grupowania kontaktów:</string>
<string name="login_account_name_required">Wymagana nazwa konta</string>
<string name="login_account_not_created">Konto nie mogło zostać stworzone</string>
<string name="login_configuration_detection">Wykrywanie konfiguracji</string>
<string name="login_querying_server">Proszę czekać, odpytywanie serwera…</string>
<string name="login_no_caldav_carddav">Nie można znaleźć usługi CalDAV lub CardDAV.</string>
<!--AccountSettingsActivity-->
<string name="settings_title">Ustawienia: %s</string>
<string name="settings_authentication">Uwierzytelnianie</string>
<string name="settings_username">Nazwa użytkownika</string>
<string name="settings_enter_username">Wpisz nazwę użytkownika:</string>
<string name="settings_password">Hasło</string>
<string name="settings_password_summary">Zaktualizuj hasło zgodnie z serwerem.</string>
<string name="settings_enter_password">Wpisz hasło:</string>
<string name="settings_certificate_alias">Alias certyfikatu klienta</string>
<string name="settings_sync">Synchronizacja</string>
<string name="settings_sync_interval_contacts">Częstotliwość synchronizacji kontaktów</string>
<string name="settings_sync_summary_manually">Tylko ręcznie</string>
<string name="settings_sync_summary_periodically" tools:ignore="PluralsCandidate">Co %d minut oraz natychmiast przy zmianach lokalnych</string>
<string name="settings_sync_interval_calendars">Częstotliwość synchronizacji kalendarzy</string>
<string name="settings_sync_interval_tasks">Częstotliwość synchronizacji list zadań</string>
<string-array name="settings_sync_interval_names">
<item>Tylko ręcznie</item>
<item>Co 15 minut</item>
<item>Co 30 minut</item>
<item>Co godzinę</item>
<item>Co 2 godziny</item>
<item>Co 4 godziny</item>
<item>Raz dziennie</item>
</string-array>
<string name="settings_sync_wifi_only">Synchronizuj tylko przez WiFi</string>
<string name="settings_sync_wifi_only_on">Synchronizacja jest ograniczona 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">
<item>GROUP_VCARDS</item>
<item>CATEGORIES</item>
</string-array>
<string name="settings_contact_group_method_change">Zmień metodę grupową</string>
<string name="settings_contact_group_method_change_reload_contacts">Wymaga to ponownego pobrania wszystkich kontaktów. Niezapisane zmiany z tego telefonu zostaną usunięte.</string>
<string name="settings_caldav">CalDAV</string>
<string name="settings_sync_time_range_past">Limit czasowy przeszłych wydarzeń</string>
<string name="settings_sync_time_range_past_none">Wszystkie wydarzenia zostaną zsynchronizowane</string>
<plurals name="settings_sync_time_range_past_days">
<item quantity="one">Wydarzenia starsze niż jeden dzień zostaną zignorowane.</item>
<item quantity="few">Wydarzenia starsze niż %d dni zostaną zignorowane.</item>
<item quantity="many">Wydarzenia starsze niż %d dni zostaną zignorowane.</item>
<item quantity="other">Wydarzenia starsze niż %d dni zostaną zignorowane.</item>
</plurals>
<string name="settings_sync_time_range_past_message">Wydarzenia, które są starsze niż podana liczba dni zostaną zignorowane (może być 0). Zostaw puste, aby synchronizować wszystkie wydarzenia.</string>
<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 kolory 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>
<string name="create_calendar">Stwórz kolekcję CalDAV</string>
<string name="create_calendar_display_name_hint">Mój kalendarz</string>
<string name="create_calendar_time_zone">Strefa czasowa:</string>
<string name="create_calendar_type">Typ kolekcji:</string>
<string name="create_calendar_type_only_events">Kalendarz (tylko wydarzenia)</string>
<string name="create_calendar_type_only_tasks">Lista zadań (tylko zadań)</string>
<string name="create_calendar_type_events_and_tasks">Połączone (wydarzenia i zadania)</string>
<string name="create_collection_color">Ustaw kolor kolekcji</string>
<string name="create_collection_creating">Tworzenie kolekcji</string>
<string name="create_collection_display_name">Nazwa wyświetlana (tytuł) kolekcji:</string>
<string name="create_collection_display_name_required">Tytuł jest wymagany</string>
<string name="create_collection_description">Opis (opcjonalnie)</string>
<string name="create_collection_home_set">Ustaw początek:</string>
<string name="create_collection_create">Stwórz</string>
<string name="delete_collection">Usuń kolekcję</string>
<string name="delete_collection_confirm_title">Czy jesteś pewien?</string>
<string name="delete_collection_confirm_warning">Kolekcja (%s) i jej wszystkie dane zostaną usunięte z serwera.</string>
<string name="delete_collection_deleting_collection">Usuwanie kolekcji</string>
<string name="collection_force_read_only">Wymuś tylko do odczytu</string>
<!--ExceptionInfoFragment-->
<string name="exception">Wystąpił błąd.</string>
<string name="exception_httpexception">Wystąpił błąd HTTP.</string>
<string name="exception_ioexception">Wystąpił błąd I/O.</string>
<string name="exception_show_details">Pokaż szczegóły</string>
<!--sync adapters and DebugInfoActivity-->
<string name="debug_info_title">Informacje debugowe</string>
<string name="sync_contacts_read_only_address_book">Książka adresowa tylko do odczytu</string>
<plurals name="sync_contacts_local_contact_changes_discarded">
<item quantity="one">Lokalny kontakt zostanie odrzucony</item>
<item quantity="few">%d lokalne kontakty zostaną odrzucone</item>
<item quantity="many">%d lokalne kontakty zostaną odrzucone</item>
<item quantity="other">%d lokalne kontakty zostaną odrzucone</item>
</plurals>
<string name="sync_error_permissions">Uprawnienia DAVdroid</string>
<string name="sync_error_permissions_text">Wymagane dodatkowe uprawnienia</string>
<string name="sync_error_opentasks_too_old">OpenTask jest niekompatybilny</string>
<string name="sync_error_opentasks_required_version">Wymagana wersja: %1$s (obecna %2$s)</string>
<!--cert4android-->
<string name="certificate_notification_connection_security">DAVdroid: Bezpieczeństwo połączenia</string>
<string name="trust_certificate_unknown_certificate_found">DAVdroid napotkał nieznany certyfikat. Czy chcesz go dodać?</string>
</resources>

View File

@@ -2,33 +2,46 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!--common strings-->
<string name="app_name">DAVdroid</string>
<string name="account_title_address_book">Livro de endereços DAVdroid</string>
<string name="address_books_authority_title">Livros de endereços</string>
<string name="help">Ajuda</string>
<string name="manage_accounts">Gerenciar contas</string>
<string name="please_wait">Por favor, aguarde...</string>
<string name="please_wait">Por favor, aguarde</string>
<string name="send">Enviar</string>
<string name="notification_channel_debugging">Depuração</string>
<string name="notification_channel_general">Outras mensagens importantes</string>
<string name="notification_channel_sync">Sincronização</string>
<string name="notification_channel_sync_errors">Erros de sincronização</string>
<string name="notification_channel_sync_io_errors">Erros de rede e E/S</string>
<string name="notification_channel_sync_status">Mensagens de status</string>
<!--startup dialogs-->
<string name="startup_autostart_permission">Sincronização automática</string>
<string name="startup_autostart_permission_message">O firmware%s frequentemente bloqueia a sincronização automática. Nesse caso, ative a sincronização automática nas configurações do seu Android.</string>
<string name="startup_battery_optimization">Sincronização agendada</string>
<string name="startup_battery_optimization_message">Seu aparelho irá restringir a sincronização do DAVdroid. Para forçar a sincronização do DAVdroid em intervalos regulares, desligue a \"otimização da bateria\".</string>
<string name="startup_battery_optimization_disable">Desligar para o DAVdroid</string>
<string name="startup_dont_show_again">Não mostrar novamente</string>
<string name="startup_development_version">Versão prévia do DAVdroid</string>
<string name="startup_development_version_message">Esta é uma versão de desenvolvimento do DAVdroid. Lembre-se de que as coisas podem não funcionar como esperado. Por favor, envie sugestões e comentários construtivos para melhorar o DAVdroid.</string>
<string name="startup_development_version_give_feedback">Enviar sugestões</string>
<string name="startup_not_now">Não agora</string>
<string name="startup_donate">Informação sobre Código Aberto</string>
<string name="startup_donate_message">Estamos felizes que você usa o DAVdroid, um software de código aberto (GPLv3). O desenvolvimento do DAVdroid é trabalhoso e consome muitas horas de trabalho. Por esse motivo, considere fazer uma doação.</string>
<string name="startup_donate_now">Mostrar a página de doações</string>
<string name="startup_donate_later">Talvez depois</string>
<string name="startup_google_play_accounts_removed">Informação sobre o erro de DRM da Play Store</string>
<string name="startup_google_play_accounts_removed_message">Sob certas condições, o DRM da Play Store pode fazer com que todas as contas DAVdroid sejam perdidas depois de uma reinicialização ou atualização do DAVdroid. Se você for afetado por esse problema, instale o \"DAVdroid JB Workaround\" a partir da Play Store.</string>
<string name="startup_google_play_accounts_removed_more_info">Mais informações</string>
<string name="startup_more_info">Mais informações</string>
<string name="startup_opentasks_not_installed">O OpenTasks não está instalado</string>
<string name="startup_opentasks_not_installed_message">O aplicativo OpenTasks não está disponível, não sendo possível sincronizar as listas de tarefas pelo DAVdroid.</string>
<string name="startup_opentasks_not_installed_message">Para sincronizar tarefas é necessário instalar o aplicativo livre OpenTasks. (Não é necessário para contatos/eventos)</string>
<string name="startup_opentasks_reinstall_davdroid">Depois da instalação do OpenTasks, torna-se necessário REINSTALAR o DAVdroid e adicionar suas contas novamente (erro do Android).</string>
<string name="startup_opentasks_not_installed_install">Instalar o OpenTasks</string>
<!--AboutActivity-->
<string name="about_license_terms">Termos da Licença</string>
<string name="about_libraries">Bibliotecas</string>
<string name="about_version">Versão %1s (%2d)</string>
<string name="about_build_date">Compilado em %s</string>
<string name="about_flavor_info">Esta versão está disponível apenas para distribuição na Google Play.</string>
<string name="about_license_info_no_warranty">Este programa é distribuído SEM NENHUMA GARANTIA. Ele é software livre e pode ser redistribuído sob algumas condições.</string>
<!--global settings-->
<string name="logging_davdroid_file_logging">Registro do arquivo do DAVdroid</string>
<string name="logging_to_external_storage">Registrando no arquivo externo: %s</string>
<string name="logging_to_external_storage_warning">Excluir os registros assim que possível!</string>
<string name="logging_couldnt_create_file">Não foi possível criar o arquivo de registro externo: %s</string>
<string name="logging_no_external_storage">Armazenamento externo não encontrado</string>
<!--AccountsActivity-->
@@ -36,14 +49,18 @@
<string name="navigation_drawer_close">Fechar gaveta de navegação</string>
<string name="navigation_drawer_subtitle">Sincronização de CalDAV/CardDAV</string>
<string name="navigation_drawer_about">Sobre / Licença</string>
<string name="navigation_drawer_beta_feedback">Comentários sobre a versão beta</string>
<string name="navigation_drawer_settings">Configurações</string>
<string name="navigation_drawer_news_updates">Novidades e atualizações</string>
<string name="navigation_drawer_external_links">Links externos</string>
<string name="navigation_drawer_website">Site na Web</string>
<string name="navigation_drawer_manual">Manual</string>
<string name="navigation_drawer_faq">Perguntas fequentes</string>
<string name="navigation_drawer_forums">Comunidade</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>
<string name="accounts_global_sync_enable">Ativar</string>
<!--DavService-->
<string name="dav_service_refresh_failed">Falha na detecção do serviço</string>
<string name="dav_service_refresh_couldnt_refresh">Não foi possível atualizar a lista da coleção</string>
@@ -53,41 +70,49 @@
<string name="app_settings_reset_hints">Restaurar sugestões</string>
<string name="app_settings_reset_hints_summary">Restaura as sugestões que foram descartadas anteriormente</string>
<string name="app_settings_reset_hints_success">Todas as sugestões serão exibidas novamente</string>
<string name="app_settings_connection">Conexão</string>
<string name="app_settings_override_proxy">Substituir as configurações de proxy</string>
<string name="app_settings_override_proxy_on">Usar configurações de proxy personalizadas</string>
<string name="app_settings_override_proxy_off">Usar configurações de proxy padrão do sistema</string>
<string name="app_settings_override_proxy_host">Nome do servidor proxy HTTP</string>
<string name="app_settings_override_proxy_port">Porta do proxy HTTP</string>
<string name="app_settings_security">Segurança</string>
<string name="app_settings_reset_trusted_certificates">Restaurar certificados confiáveis</string>
<string name="app_settings_reset_trusted_certificates_summary">Esquece de todos os certificados que foram aceitos anteriormente</string>
<plurals name="app_settings_reset_trusted_certificates_success">
<item quantity="one">Retirada a confiança de um certificado</item>
<item quantity="other">Retirada a confiança de %d certificados</item>
</plurals>
<string name="app_settings_distrust_system_certs">Desconfiar dos certificados de sistema</string>
<string name="app_settings_distrust_system_certs_on">ACs adicionadas pelo usuário e pelo sistema não serão confiáveis</string>
<string name="app_settings_distrust_system_certs_off">ACs adicionadas pelo usuário e pelo sistema serão confiáveis (recomendado)</string>
<string name="app_settings_reset_certificates">Restaurar certificados não-confiáveis</string>
<string name="app_settings_reset_certificates_summary">Restaura a confiança de todos os certificados personalizados</string>
<string name="app_settings_reset_certificates_success">Todos os certificados personalizados foram restaurados</string>
<string name="app_settings_debug">Depuração</string>
<string name="app_settings_log_to_external_storage">Registrar em arquivo externo</string>
<string name="app_settings_log_to_external_storage_on">Registrando no armazenamento externo (se disponível)</string>
<string name="app_settings_log_to_external_storage_off">O registro em arquivo externo está desativado</string>
<string name="app_settings_show_debug_info">Mostrar informações de depuração</string>
<string name="app_settings_show_debug_info_details">Exibir/compartilhar o software e os detalhes da configuração</string>
<string name="app_settings_show_debug_info_details">Exibe/compartilha o software e os detalhes da configuração</string>
<!--AccountActivity-->
<string name="account_synchronize_now">Sincronizar agora</string>
<string name="account_synchronizing_now">Sincronizando</string>
<string name="account_settings">Configurações da conta</string>
<string name="account_rename">Renomear conta</string>
<string name="account_rename_new_name">Dados locais que não foram salvos podem ser descartados. É necessário efetuar uma nova sincronização após renomear. Novo nome da conta:</string>
<string name="account_rename_rename">Renomear</string>
<string name="account_delete">Excluir conta</string>
<string name="account_delete_confirmation_title">Deseja excluir a conta?</string>
<string name="account_delete_confirmation_text">Todas as cópias locais dos livros de endereços, calendários e listas de tarefas serão excluídas.</string>
<string name="account_select_collections_hint">Selecione as coleções a sincronizar</string>
<string name="account_carddav">CardDAV</string>
<string name="account_caldav">CalDAV</string>
<string name="account_webcal">Webcal</string>
<string name="account_synchronize_this_collection">sincronizar esta coleção</string>
<string name="account_read_only">Somente leitura</string>
<string name="account_calendar">calendário</string>
<string name="account_task_list">lista de tarefas</string>
<string name="account_refresh_address_book_list">Atualizar lista de livros de endereços</string>
<string name="account_create_new_address_book">Criar novo livro de endereços</string>
<string name="account_refresh_calendar_list">Atualizar lista de calendários</string>
<string name="account_create_new_calendar">Criar novo calendário</string>
<!--PermissionsActivity-->
<string name="permissions_title">Permissões do DAVdroid</string>
<string name="permissions_calendar">Permissões do calendário</string>
<string name="permissions_calendar_details">Para sincronizar os eventos CalDAV com seus calendários locais, o DAVdroid precisa acessar seus calendários.</string>
<string name="permissions_calendar_request">Solicitar permissão do calendário</string>
<string name="permissions_contacts">Permissões dos contados</string>
<string name="permissions_contacts_details">Para sincronizar livros de endereços CardDAV com seus contatos locais, o DAVdroid precisa acessar seus contatos.</string>
<string name="permissions_contacts_request">Solicitar permissão dos contatos</string>
<string name="permissions_opentasks">Permissões do OpenTasks</string>
<string name="permissions_opentasks_details">Para sincronizar tarefas CalDAV com suas listas de tarefas locais, o DAVdroid precisa acessar o OpenTasks.</string>
<string name="permissions_opentasks_request">Solicitar permissão do OpenTasks</string>
<string name="account_no_webcal_handler_found">Não foi encontrado um aplicativo capaz de lidar com Webcal</string>
<string name="account_install_icsdroid">Instalar ICSdroid</string>
<!--AddAccountActivity-->
<string name="login_title">Adicionar conta</string>
<string name="login_type_email">Autenticação com endereço de e-mail</string>
@@ -97,11 +122,13 @@
<string name="login_password_required">É necessário uma senha</string>
<string name="login_type_url">Autenticação com usuário e URL</string>
<string name="login_url_must_be_http_or_https">A URL deve começar com http(s)://</string>
<string name="login_url_must_be_https">A URL deve começar com https://</string>
<string name="login_url_host_name_required">É necessário um nome de máquina</string>
<string name="login_user_name">Usuário</string>
<string name="login_user_name_required">É necessário um nome de usuário</string>
<string name="login_base_url">URL base</string>
<string name="login_auth_preemptive">Autenticação preferencial (recomendado, mas incompatível com autenticação Digest)</string>
<string name="login_type_url_certificate">Autenticação com URL e certificado do cliente</string>
<string name="login_select_certificate">Selecionar certificado</string>
<string name="login_login">Autenticar</string>
<string name="login_back">Voltar</string>
<string name="login_create_account">Criar conta</string>
@@ -111,9 +138,9 @@
<string name="login_account_name_required">É necessário um nome de conta</string>
<string name="login_account_not_created">A conta não pôde ser criada</string>
<string name="login_configuration_detection">Detecção de configuração</string>
<string name="login_querying_server">Aguarde, procurando servidor...</string>
<string name="login_querying_server">Aguarde, procurando servidor</string>
<string name="login_no_caldav_carddav">Não foi possível encontrar o serviço CalDAV ou CardDAV.</string>
<string name="login_view_logs">Exibir registros</string>
<string name="login_view_logs">Mostrar detalhes</string>
<!--AccountSettingsActivity-->
<string name="settings_title">Configurações: %s</string>
<string name="settings_authentication">Autenticação</string>
@@ -122,31 +149,17 @@
<string name="settings_password">Senha</string>
<string name="settings_password_summary">Atualize a senha de acordo com seu servidor</string>
<string name="settings_enter_password">Digite sua senha:</string>
<string name="settings_preemptive">Autenticação preferencial</string>
<string name="settings_preemptive_on">Credenciais enviadas a cada requisição (recomendado)</string>
<string name="settings_preemptive_off">Credenciais enviadas após a requisição do servidor</string>
<string name="settings_certificate_alias">Nome do certificado do cliente</string>
<string name="settings_sync">Sincronização</string>
<string name="settings_sync_interval_contacts">Intervalo sinc. de contatos</string>
<string name="settings_sync_summary_manually">Apenas manualmente</string>
<string name="settings_sync_summary_periodically" tools:ignore="PluralsCandidate">A cada %d minutos + imediatamente nas alterações locais</string>
<string name="settings_sync_summary_not_available">Indisponível</string>
<string name="settings_sync_interval_calendars">Intervalo sinc. de calendários</string>
<string name="settings_sync_interval_tasks">Intervalo sinc. de tarefas</string>
<string-array name="settings_sync_interval_seconds">
<item>-1</item>
<item>300</item>
<item>600</item>
<item>900</item>
<item>3600</item>
<item>7200</item>
<item>14400</item>
<item>86400</item>
</string-array>
<string-array name="settings_sync_interval_names">
<item>Apenas manualmente</item>
<item>A cada 5 minutos</item>
<item>A cada 10 minutos</item>
<item>A cada 15 minutos</item>
<item>A cada 30 minutos</item>
<item>A cada hora</item>
<item>A cada 2 horas</item>
<item>A cada 4 horas</item>
@@ -155,10 +168,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_ssid">Restrição de SSID Wi-Fi</string>
<string name="settings_sync_wifi_only_ssid_on">Sincronizará apenas com %s</string>
<string name="settings_sync_wifi_only_ssid_off">Qualquer conexão Wi-Fi pode ser utilizada</string>
<string name="settings_sync_wifi_only_ssid_message">Informe o nome da rede Wi-Fi (SSID) que será usada para sincronização ou deixe em branco para usar qualquer conexão Wi-Fi.</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">
@@ -169,9 +182,8 @@
<item>Grupos são VCards separados</item>
<item>Grupos são categorias por contato</item>
</string-array>
<string name="settings_rfc6868_for_vcards">Usar RFC6868 para VCards</string>
<string name="settings_rfc6868_for_vcards_on">Aspas podem ser utilizadas nos valores dos parâmetros</string>
<string name="settings_rfc6868_for_vcards_off">Aspas não podem ser utilizadas nos valores dos parâmetros</string>
<string name="settings_contact_group_method_change">Alterar a forma de agrupamento</string>
<string name="settings_contact_group_method_change_reload_contacts">É necessário recarregar todos os contatos. As alterações locais que não foram salvas serão descartadas.</string>
<string name="settings_caldav">CalDAV</string>
<string name="settings_sync_time_range_past">Limite de tempo para eventos passados</string>
<string name="settings_sync_time_range_past_none">Todos os eventos serão sincronizados</string>
@@ -183,9 +195,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_version_update">Atualização da versão do DAVdroid</string>
<string name="settings_version_update_settings_updated">As configurações internas foram atualizadas.</string>
<string name="settings_version_update_install_hint">Problemas? Desinstale o DAVdroid e instale novamente.</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>
@@ -207,34 +220,33 @@
<string name="delete_collection_confirm_title">Tem certeza?</string>
<string name="delete_collection_confirm_warning">Esta coleção (%s) e todos os seus dados serão removidos do servidor.</string>
<string name="delete_collection_deleting_collection">Excluindo coleção</string>
<string name="collection_force_read_only">Forçar somente leitura</string>
<string name="collection_properties">Propriedades</string>
<string name="collection_properties_url">Endereço (URL):</string>
<string name="collection_properties_copy_url">Copiar URL</string>
<!--ExceptionInfoFragment-->
<string name="exception">Ocorreu um erro.</string>
<string name="exception_httpexception">Ocorreu um erro de HTTP.</string>
<string name="exception_ioexception">Ocorreu um erro de leitura/gravação.</string>
<string name="exception_show_details">Mostrar detalhes</string>
<!--sync errors and DebugInfoActivity-->
<!--sync adapters and DebugInfoActivity-->
<string name="debug_info_title">Informações de depuração</string>
<string name="sync_contacts_read_only_address_book">Livro de endereços somente leitura</string>
<plurals name="sync_contacts_local_contact_changes_discarded">
<item quantity="one">Alteração local de contato descartada</item>
<item quantity="other">%d alterações locais de contatos descartadas</item>
</plurals>
<string name="sync_error_permissions">Permissões do DAVdroid</string>
<string name="sync_error_permissions_text">É necessário permissões adicionais</string>
<string name="sync_error_calendar">Falha na sincronização do calendário (%s)</string>
<string name="sync_error_contacts">Falha na sincronização do livro de endereços (%s)</string>
<string name="sync_error_tasks">Falha na sincronização das tarefas (%s)</string>
<string name="sync_error">Erro ao %s</string>
<string name="sync_error_http_dav">Erro do servidor ao %s</string>
<string name="sync_error_local_storage">Erro do banco de dados ao %s</string>
<string-array name="sync_error_phases">
<item>preparando sincronização</item>
<item>procurando habilidades</item>
<item>processando os itens excluídos localmente</item>
<item>preparando os itens criados/modificados</item>
<item>enviando os itens criados/modificados</item>
<item>verificando o estado da sincronização</item>
<item>listando os itens locais</item>
<item>listando os itens remotos</item>
<item>comparando os itens locais/remotos</item>
<item>baixando os itens remotos</item>
<item>pós-processamento</item>
<item>salvando o estado da sincronização</item>
</string-array>
<string name="sync_error_unauthorized">Usuário/senha incorreto</string>
<string name="sync_error_opentasks_too_old">A versão do OpenTasks é muito antiga</string>
<string name="sync_error_opentasks_required_version">Versão necessária: %1$s (atual %2$s)</string>
<string name="sync_error_authentication_failed">Falha de autenticação (verifique as credenciais)</string>
<string name="sync_error_io">Erro de rede ou E/S %s</string>
<string name="sync_error_http_dav">Erro no servidor HTTP %s</string>
<string name="sync_error_local_storage">Erro de armazenamento local %s</string>
<string name="sync_error_retry">Repetir</string>
<string name="sync_error_view_item">Ver item</string>
<!--cert4android-->
<string name="certificate_notification_connection_security">DAVdroid: Segurança da conexão</string>
<string name="trust_certificate_unknown_certificate_found">O DAVdroid encontrou um certificado desconhecido. Deseja torná-lo confiável?</string>
</resources>

View File

@@ -10,11 +10,9 @@
<!--DavService-->
<!--AppSettingsActivity-->
<!--AccountActivity-->
<!--PermissionsActivity-->
<!--AddAccountActivity-->
<string name="login_type_email">Login com seu enderço de email</string>
<string name="login_type_url">Login com URL e nome do usuário</string>
<string name="login_auth_preemptive">Autenticação preferida (recomendado, mas incompatível com Digest)</string>
<!--AccountSettingsActivity-->
<string name="settings_authentication">Autenticação</string>
<string name="settings_username">Nome de usuário</string>
@@ -22,36 +20,13 @@
<string name="settings_password">Senha</string>
<string name="settings_password_summary">Atualize sua denha de acordo com a do seu servidor.</string>
<string name="settings_enter_password">Informe sua senha:</string>
<string name="settings_preemptive">Pre-emptive authentication</string>
<string name="settings_preemptive_on">Credenciais são enviadas com cadas requisição (recomendado)</string>
<string name="settings_preemptive_off">Credenciais são enviadas apos o servidor requisitar</string>
<string name="settings_sync">Sincronização</string>
<string name="settings_sync_interval_contacts">Intervalo de sincronização dos contatos</string>
<string name="settings_sync_summary_manually">Manualmente apenas</string>
<string name="settings_sync_summary_periodically" tools:ignore="PluralsCandidate">A cada %d minutos + imediatamente em alterações locais</string>
<string name="settings_sync_summary_not_available">Não avaliado</string>
<string name="settings_sync_interval_calendars">Intervalo de sincronização do calendário</string>
<string-array name="settings_sync_interval_seconds">
<item>-1</item>
<item>300</item>
<item>600</item>
<item>900</item>
<item>3600</item>
<item>7200</item>
<item>14400</item>
<item>86400</item>
</string-array>
<string-array name="settings_sync_interval_names">
<item>Apenas manualmente</item>
<item>A cada 5 minutos</item>
<item>A cada 10 minutos</item>
<item>A cada 15 minutos</item>
<item>A cada hora</item>
<item>A cada 2 horas</item>
<item>A cada 4 horas</item>
<item>Diáriamente</item>
</string-array>
<!--collection management-->
<!--ExceptionInfoFragment-->
<!--sync errors and DebugInfoActivity-->
<!--sync adapters and DebugInfoActivity-->
<!--cert4android-->
</resources>

View File

@@ -0,0 +1,256 @@
<?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="notification_channel_debugging">Отладка</string>
<string name="notification_channel_general">Другие важные сообщения</string>
<string name="notification_channel_sync">Синхронизация</string>
<string name="notification_channel_sync_errors">Ошибки синхронизации</string>
<string name="notification_channel_sync_io_errors">Ошибки сети и ввода/вывода</string>
<string name="notification_channel_sync_status">Сообщения о состоянии</string>
<!--startup dialogs-->
<string name="startup_autostart_permission">Автоматическая синхронизация</string>
<string name="startup_autostart_permission_message">%s ПО устройства часто блокирует автоматическую синхронизацию. В этом случае разрешите автоматическую синхронизацию в настройках Android.</string>
<string name="startup_battery_optimization">Синхронизация по расписанию</string>
<string name="startup_battery_optimization_message">Ваше устройство будет блокировать синхронизацию DAVdroid. Чтобы обеспечить регулярные интервалы синхронизации DAVdroid, отключите оптимизацию энергопотребления.</string>
<string name="startup_battery_optimization_disable">Отключить для DAVdroid</string>
<string name="startup_dont_show_again">Не показывать снова</string>
<string name="startup_not_now">Не сейчас</string>
<string name="startup_donate">Open-Source информация</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 Store DRM</string>
<string name="startup_google_play_accounts_removed_message">При определенных условиях Play Store DRM может стать причиной потери всех DAVdroid аккаунтов после перезагрузки устройства или после обновления DAVdroid. Если Вы столкнулись с этой проблемой (и только в этом случае), установите \"DAVdroid JB Workaround\" из Play Store.</string>
<string name="startup_more_info">Дополнительная информация</string>
<string name="startup_opentasks_not_installed">OpenTasks не установлен</string>
<string name="startup_opentasks_not_installed_message">Для синхронизации задач требуется бесплатное приложение OpenTasks. (Не требуется для контактов/событий.)</string>
<string name="startup_opentasks_reinstall_davdroid">После установки OpenTasks необходимо ПЕРЕУСТАНОВИТЬ DAVdroid и повторно добавить ваши аккаунты (проблема Android).</string>
<string name="startup_opentasks_not_installed_install">Установить OpenTasks</string>
<!--AboutActivity-->
<string name="about_libraries">Библиотеки</string>
<string name="about_version">Версия %1s (%2d)</string>
<string name="about_build_date">Скомпилировано %s</string>
<string name="about_flavor_info">Эта версия распространяется только через Google Play.</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_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_beta_feedback">Отзыв о бета-тестировании</string>
<string name="navigation_drawer_settings">Настройки</string>
<string name="navigation_drawer_news_updates">Новости &amp; обновления</string>
<string name="navigation_drawer_external_links">Внешние ссылки</string>
<string name="navigation_drawer_website">Веб-сайт</string>
<string name="navigation_drawer_manual">Руководство</string>
<string name="navigation_drawer_faq">FAQ</string>
<string name="navigation_drawer_forums">Помощь / Форумы</string>
<string name="navigation_drawer_donate">Пожертвовать</string>
<string name="account_list_empty">Добро пожаловать в DAVdroid\n\nТеперь вы можете добавить аккаунт CalDAV/CardDAV.</string>
<string name="accounts_global_sync_disabled">Синхронизация отключена на уровне устройства</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">Не доверять системным и добавленным пользователем CA</string>
<string name="app_settings_distrust_system_certs_off">Доверять системным и добавленным пользователем CA (рекомендуется)</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_select_collections_hint">Выберите коллекции для синхронизации</string>
<string name="account_carddav">CardDAV</string>
<string name="account_caldav">CalDAV</string>
<string name="account_webcal">WebСal</string>
<string name="account_synchronize_this_collection">синхронизировать эту коллекцию</string>
<string name="account_read_only">только для чтения</string>
<string name="account_calendar">календарь</string>
<string name="account_task_list">список задач</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>
<string name="account_no_webcal_handler_found">Не найдено приложение, поддерживающее WebCal</string>
<string name="account_install_icsdroid">Установить ICSdroid</string>
<!--AddAccountActivity-->
<string name="login_title">Добавить аккаунт</string>
<string name="login_type_email">Вход с адресом электронной почты</string>
<string name="login_email_address">Адрес электронной почты</string>
<string name="login_email_address_error">Требуется действующий адрес электронной почты</string>
<string name="login_password">Пароль</string>
<string name="login_password_required">Требуется пароль</string>
<string name="login_type_url">Вход с URL и именем пользователя</string>
<string name="login_url_must_be_http_or_https">URL должен начинаться с http(s)://</string>
<string name="login_url_must_be_https">URL-адрес должен начинаться с https://</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_type_url_certificate">Войти с URL-адресом и сертификатом клиента</string>
<string name="login_select_certificate">Выберите сертификат</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">Используйте ваш адрес адрес электронной почты в качестве имени аккаунта, поскольку Android будет использовать имя аккаунта в поле ORGANIZER для событий, которые вы создаете. У вас не может быть двух аккаунтов с тем же именем.</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_certificate_alias">Псевдоним сертификата клиента</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>Каждые 15 минут</item>
<item>Каждые 30 минут</item>
<item>Каждый час</item>
<item>Каждые 2 часа</item>
<item>Каждые 4 часа</item>
<item>Один раз в день</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_sync_wifi_only_ssids">Ограничение WiFi SSID</string>
<string name="settings_sync_wifi_only_ssids_on">Будет синхронизироваться только %s</string>
<string name="settings_sync_wifi_only_ssids_off">Все соединения WiFi будут использоваться</string>
<string name="settings_sync_wifi_only_ssids_message">Названия (SSID), разделенные запятыми разрешенных сетей Wi-Fi (оставьте пустым для всех)</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>Группы являются отдельными vCards</item>
<item>Группы являются категориями контактов</item>
</string-array>
<string name="settings_contact_group_method_change">Изменить метод группировки</string>
<string name="settings_contact_group_method_change_reload_contacts">Вам потребуется перезагрузить все контакты. Несохраненные локальные изменения будут отброшены.</string>
<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="one">События старше одного дня будут игнорироваться</item>
<item quantity="few">События старше %d дней будут игнорироваться</item>
<item quantity="many">События старше %d дней будут игнорироваться</item>
<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>
<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>
<string name="create_calendar">Создать коллекцию CalDAV</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">Адрес каталога:</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>
<string name="collection_force_read_only">Только для чтения</string>
<string name="collection_properties">Свойства</string>
<string name="collection_properties_url">Адрес (URL):</string>
<string name="collection_properties_copy_url">Копировать URL</string>
<!--ExceptionInfoFragment-->
<string name="exception">Произошла ошибка.</string>
<string name="exception_httpexception">Произошла ошибка HTTP</string>
<string name="exception_ioexception">Произошла ошибка ввода/вывода.</string>
<string name="exception_show_details">Показать детали</string>
<!--sync adapters and DebugInfoActivity-->
<string name="debug_info_title">Отладочная информация</string>
<string name="sync_contacts_read_only_address_book">Адресная книга только для чтения</string>
<plurals name="sync_contacts_local_contact_changes_discarded">
<item quantity="one">Локальное изменение контакта отменено</item>
<item quantity="few">%d локальных изменений контакта отменены</item>
<item quantity="many">%d локальных изменений контакта отменены</item>
<item quantity="other">%d локальных изменений контакта отменены</item>
</plurals>
<string name="sync_error_permissions">Разрешения DAVdroid</string>
<string name="sync_error_permissions_text">Требуются дополнительные разрешения</string>
<string name="sync_error_opentasks_too_old">OpenTasks устарел</string>
<string name="sync_error_opentasks_required_version">Требуется версия: %1$s (текущая %2$s)</string>
<string name="sync_error_authentication_failed">Ошибка аутентификации (проверьте учетные данные)</string>
<string name="sync_error_io">Ошибка сети или ввода/вывода %s</string>
<string name="sync_error_http_dav">Ошибка HTTP-сервера %s</string>
<string name="sync_error_local_storage">Ошибка локального хранилища %s</string>
<string name="sync_error_retry">Повторить</string>
<string name="sync_error_view_item">Просмотр элемента</string>
<!--cert4android-->
<string name="certificate_notification_connection_security">DAVdroid: безопасность подключения</string>
<string name="trust_certificate_unknown_certificate_found">DAVdroid обнаружил неизвестный сертификат. Вы хотите доверять ему?</string>
</resources>

View File

@@ -2,33 +2,29 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!--common strings-->
<string name="app_name">ДАВдроид</string>
<string name="account_title_address_book">ДАВдроид адресар</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>
<!--startup dialogs-->
<string name="startup_battery_optimization_disable">Искључи за ДАВдроид</string>
<string name="startup_dont_show_again">Не приказуј поново</string>
<string name="startup_development_version">ДАВдроид прелиминарно издање</string>
<string name="startup_development_version_message">Ово је развојно издање ДАВдроида. Имајте на уму да можда неће радити очекивано. Замољавамо вас за конструктивне повратне информације како бисмо га побољшали.</string>
<string name="startup_development_version_give_feedback">Повратне информације</string>
<string name="startup_donate">Подаци о отвореном кôду</string>
<string name="startup_donate_message">Драго нам је да користите ДАВдроид, софтвер отвореног кôда (ГПЛв3). Развој ДАВдроида није баш лак посао и захтева хиљаде радних сати, стога вас молимо да размотрите донацију.</string>
<string name="startup_donate_now">Прикажи страницу за донације</string>
<string name="startup_donate_later">Можда касније</string>
<string name="startup_google_play_accounts_removed">Грешка ДРМ-а Плеј продавнице</string>
<string name="startup_google_play_accounts_removed_message">Под одређеним околностима ДРМ Плеј продавнице може да узрокује да сви налози ДАВдроида нестане након рестарта или ажурирања ДАВдроида. Ако и само ако имате овај проблем, инсталирајте „DAVdroid JB Workaround“ са Плеј продавнице.</string>
<string name="startup_google_play_accounts_removed_more_info">Још информација</string>
<string name="startup_opentasks_not_installed">Отворени задаци нису инсталирани</string>
<string name="startup_opentasks_not_installed_message">Отворени задаци нису доступни па ДАВдроид неће моћи да синхронизује листе задатака. </string>
<string name="startup_opentasks_reinstall_davdroid">Након инсталирања Отворених задатака, морате поново да инсталирате ДАВдроид и поново додате ваше налоге (због грешке у Андроиду).</string>
<string name="startup_opentasks_not_installed_install">Инсталирај Отворене задатке</string>
<!--AboutActivity-->
<string name="about_license_terms">Услови лиценце</string>
<string name="about_license_info_no_warranty">Овај програм НЕМА НИКАКВЕ ГАРАНЦИЈЕ. Бесплатан је софтвер којег можете слободно да делите под одређеним условима.</string>
<!--global settings-->
<string name="logging_davdroid_file_logging">ДАВдроид евиденција</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-->
@@ -41,9 +37,10 @@
<string name="navigation_drawer_external_links">Вањске везе</string>
<string name="navigation_drawer_website">Веб-сајт</string>
<string name="navigation_drawer_faq">ЧПП</string>
<string name="navigation_drawer_forums">Заједница</string>
<string name="navigation_drawer_donate">Донирај</string>
<string name="account_list_empty">Добро дошли у ДАВдроид!\n\nМожете сада да додате КалДАВ/КардДАВ налог.</string>
<string name="accounts_global_sync_disabled">Синхронизација је системски искључена</string>
<string name="accounts_global_sync_enable">Укључи</string>
<!--DavService-->
<string name="dav_service_refresh_failed">Откривање услуге није успело</string>
<string name="dav_service_refresh_couldnt_refresh">Не могох да освежим списак збирки</string>
@@ -53,14 +50,19 @@
<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">ХТТП прокси домаћин</string>
<string name="app_settings_override_proxy_port">ХТТП прокси порт</string>
<string name="app_settings_security">Безбедност</string>
<string name="app_settings_reset_trusted_certificates">Ресетуј поуздане сертификате</string>
<string name="app_settings_reset_trusted_certificates_summary">Заборављање претходно прихваћених сертификата</string>
<plurals name="app_settings_reset_trusted_certificates_success">
<item quantity="one">Посумњано у један сертификат</item>
<item quantity="few">Посумњано у %d сертификата</item>
<item quantity="other">Посумњано у %d сертификата</item>
</plurals>
<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>
@@ -71,6 +73,9 @@
<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>
@@ -78,17 +83,6 @@
<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">ДАВдроид дозволе</string>
<string name="permissions_calendar">Дозволе за календар</string>
<string name="permissions_calendar_details">Да би синхронизовао КалДАВ догађаје са вашим локалним календарима, ДАВдроиду треба приступ вашим календарима.</string>
<string name="permissions_calendar_request">Захтевај дозволе за календар</string>
<string name="permissions_contacts">Дозволе за контакте</string>
<string name="permissions_contacts_details">Да би синхронизовао КардДАВ адресаре са вашим локалним контактима, ДАВдроиду треба приступ вашим контактима.</string>
<string name="permissions_contacts_request">Захтевај дозволе за контакте</string>
<string name="permissions_opentasks">Дозволе за задатке</string>
<string name="permissions_opentasks_details">Да би синхронизовао КалДАВ задатке са вашим локалним листама задатака, ДАВдроиду треба приступ Задацима.</string>
<string name="permissions_opentasks_request">Захтевај дозволе за задатке</string>
<!--AddAccountActivity-->
<string name="login_title">Додај налог</string>
<string name="login_type_email">Пријавите се адресом е-поште</string>
@@ -102,7 +96,6 @@
<string name="login_user_name">Корисничко име</string>
<string name="login_user_name_required">Корисничко име је обавезно</string>
<string name="login_base_url">Корени УРЛ</string>
<string name="login_auth_preemptive">Превентивна аутентификација (препоручено, али некомпатибилно са Дигест аутентификацијом)</string>
<string name="login_login">Пријава</string>
<string name="login_back">Назад</string>
<string name="login_create_account">Направи налог</string>
@@ -114,7 +107,6 @@
<string name="login_configuration_detection">Откривање конфигурације</string>
<string name="login_querying_server">Сачекајте, шаљем упит серверу…</string>
<string name="login_no_caldav_carddav">Не могох да нађем КалДАВ или КардДАВ услугу.</string>
<string name="login_view_logs">Прикажи записе</string>
<!--AccountSettingsActivity-->
<string name="settings_title">Поставке: %s</string>
<string name="settings_authentication">Аутентификација</string>
@@ -123,43 +115,15 @@
<string name="settings_password">Лозинка</string>
<string name="settings_password_summary">Ажурирајте лозинку за ваш сервер.</string>
<string name="settings_enter_password">Унесите лозинку:</string>
<string name="settings_preemptive">Превентивна аутентификација</string>
<string name="settings_preemptive_on">Слање акредитива са сваким захтевом (препоручено)</string>
<string name="settings_preemptive_off">Слање акредитива по захтеву сервера</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_summary_not_available">Није доступно</string>
<string name="settings_sync_interval_calendars">Интервал синх. календара</string>
<string name="settings_sync_interval_tasks">Интервал синх. задатака</string>
<string-array name="settings_sync_interval_seconds">
<item>-1</item>
<item>300</item>
<item>600</item>
<item>900</item>
<item>3600</item>
<item>7200</item>
<item>14400</item>
<item>86400</item>
</string-array>
<string-array name="settings_sync_interval_names">
<item>Само ручно</item>
<item>Сваких 5 минута</item>
<item>Сваких 10 минута</item>
<item>Сваких 15 минута</item>
<item>Сваког сата</item>
<item>Свака 2 сата</item>
<item>Свака 4 сата</item>
<item>Једном дневно</item>
</string-array>
<string name="settings_sync_wifi_only">Само преко бежичног</string>
<string name="settings_sync_wifi_only_on">Синхронизовање само преко бежичних мрежа</string>
<string name="settings_sync_wifi_only_off">Тип везе није узет у обзир</string>
<string name="settings_sync_wifi_only_ssid">Ограничења ССИД-а бежичних</string>
<string name="settings_sync_wifi_only_ssid_on">Синхронизовање само преко %s</string>
<string name="settings_sync_wifi_only_ssid_off">Коришћење свих бежичних мрежа</string>
<string name="settings_sync_wifi_only_ssid_message">Унесите назив бежичне мреже (њен ССИД) да бисте ограничили синхронизацију само на ту мрежу, или оставите празно за синхронизовање преко било које бежичне мреже.</string>
<string name="settings_carddav">КардДАВ</string>
<string name="settings_contact_group_method">Режим група контаката</string>
<string-array name="settings_contact_group_method_values">
@@ -170,9 +134,6 @@
<item>Групе су одвојене В-карте</item>
<item>Групе су категорије по контакту</item>
</string-array>
<string name="settings_rfc6868_for_vcards">Користи РФЦ6868 за В-карте</string>
<string name="settings_rfc6868_for_vcards_on">Двоструки наводници могу да се користе у вредностима параметара</string>
<string name="settings_rfc6868_for_vcards_off">Двоструки наводници не могу да се користе у вредностима параметара</string>
<string name="settings_caldav">КалДАВ</string>
<string name="settings_sync_time_range_past">Ограничење догађаја у прошлости</string>
<string name="settings_sync_time_range_past_none">Сви догађаји се синхронизују</string>
@@ -185,9 +146,6 @@
<string name="settings_manage_calendar_colors">Управљај бојама календара</string>
<string name="settings_manage_calendar_colors_on">Бојама календара управља ДАВдроид</string>
<string name="settings_manage_calendar_colors_off">Боје календара није поставио ДАВдроид</string>
<string name="settings_version_update">Надоградња ДАВдроид издања</string>
<string name="settings_version_update_settings_updated">Унутрашње поставке су ажуриране.</string>
<string name="settings_version_update_install_hint">Проблеми? Уклоните ДАВдроид па га поново инсталирајте.</string>
<!--collection management-->
<string name="create_addressbook">Направи адресар</string>
<string name="create_addressbook_display_name_hint">Мој адресар</string>
@@ -214,29 +172,11 @@
<string name="exception_httpexception">Десила се ХТТП грешка.</string>
<string name="exception_ioexception">Десила се У/И грешка.</string>
<string name="exception_show_details">Прикажи детаље</string>
<!--sync errors and DebugInfoActivity-->
<!--sync adapters and DebugInfoActivity-->
<string name="debug_info_title">Подаци за исправљање грешака</string>
<string name="sync_error_permissions">ДАВдроид дозволе</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">ДАВдроид: Безбедност везе</string>
<string name="trust_certificate_unknown_certificate_found">ДАВдроид је наишао на непознат сертификат. Желите ли да се поуздате у њега?</string>
</resources>

View File

@@ -4,31 +4,24 @@
<string name="app_name">DAVdroid</string>
<string name="help">Yardım</string>
<string name="manage_accounts">Hesapları yönet</string>
<string name="please_wait">Lütfen bekle ...</string>
<string name="please_wait">Lütfen bekle </string>
<string name="send">Gönder</string>
<!--startup dialogs-->
<string name="startup_dont_show_again">Bir daha gösterme</string>
<string name="startup_development_version">DAVDroid Önizlenim Dağıtımı</string>
<string name="startup_development_version_message">Bu DAVdroid\'in bir geliştirme sürümüdür. Bazı şeyler beklendiği gibi çalışmayabilir. DAVdroid\'i iyileştirmek için bize lütfen yapıcı eleştirilerini ilet.</string>
<string name="startup_development_version_give_feedback">Geribildirim ver</string>
<string name="startup_donate">ık-Kaynak Bilgisi</string>
<string name="startup_donate_message">ık kaynaklı yazılım (GPLv3) olan DAVdroid\'i kullandığına çok mutluyuz. DAVdroid\'i geliştirmek zor bir iş ve üzerinde binlerce saat çalıştığımızdan, lütfen bir bağışta bulunmayı düşün.</string>
<string name="startup_donate_now">Bağış sayfasını göster</string>
<string name="startup_donate_later">Belki sonra</string>
<string name="startup_google_play_accounts_removed">Play Store DRM hata bilgisi</string>
<string name="startup_google_play_accounts_removed_message">Bazı durumlarda Play Store DRM\'i, cihazı yeniden başlatınca veya DAVdroid\'i yükseltince DAVdroid hesaplarının yokolmasına sebep olabiliyor. Bu sorundan etkileniyorsan (ve sadece bu durumda), lütfen Play Store\'daki \"DAVdroid JB Workaround\" uygulamasını kur.</string>
<string name="startup_google_play_accounts_removed_more_info">Daha fazla bilgi</string>
<string name="startup_opentasks_not_installed">OpenTasks kurulu değil</string>
<string name="startup_opentasks_not_installed_message">OpenTasks uygulaması yok, dolayısıyla DAVdroid iş listelerini senkronize edemeyecektir.</string>
<string name="startup_opentasks_reinstall_davdroid">OpenTasks\'i kurduktan sonra, DAVdroid\'i YENİDEN KURMAN ve hesaplarını yeniden eklemen gerek. (Android hatası).</string>
<string name="startup_opentasks_not_installed_install">OpenTasks kur</string>
<!--AboutActivity-->
<string name="about_license_terms">Lisans şartları</string>
<string name="about_license_info_no_warranty">Bu uygulama HİÇ BİR GARANTİ ile gelmemektedir. Bedava bir yazılımdır ve belli koşullar altında dağıtabilirsiniz.</string>
<!--global settings-->
<string name="logging_davdroid_file_logging">DAVdroid dosya jurnallemesi</string>
<string name="logging_to_external_storage">Harici depolamaya jurnalleniyor: %s</string>
<string name="logging_to_external_storage_warning">Jurnalleri bir an önce silin!</string>
<string name="logging_couldnt_create_file">Harici jurnal dosyası yaratılamadı: %s </string>
<string name="logging_no_external_storage">Harici depolama alanı bulunamadı</string>
<!--AccountsActivity-->
@@ -41,7 +34,6 @@
<string name="navigation_drawer_external_links">Harici bağlantılar</string>
<string name="navigation_drawer_website">Web sitesi</string>
<string name="navigation_drawer_faq">SSS</string>
<string name="navigation_drawer_forums">Camia</string>
<string name="navigation_drawer_donate">Bağış yap</string>
<string name="account_list_empty">DAVdroid\'e hoşgeldin!\n\nŞimdi bir CalDAV/CardDAV hesabı ekleyebilirsin.</string>
<!--DavService-->
@@ -54,11 +46,6 @@
<string name="app_settings_reset_hints_summary">Daha önceden azat edilen ipuçlarını yeniden etkinleştirir</string>
<string name="app_settings_reset_hints_success">Tüm ipuçları artık gösterilecek</string>
<string name="app_settings_security">Güvenlik</string>
<string name="app_settings_reset_trusted_certificates">Güvenilen sertifikaları sıfırla</string>
<string name="app_settings_reset_trusted_certificates_summary">Daha önceden kabul edilmiş tüm sertifikaları unutur</string>
<plurals name="app_settings_reset_trusted_certificates_success">
<item quantity="other">Güvenilmeyen %d sertifikaları</item>
</plurals>
<string name="app_settings_debug">Hata ayıklama</string>
<string name="app_settings_log_to_external_storage">Harici dosyaya jurnalle</string>
<string name="app_settings_log_to_external_storage_on">Harici depolamaya jurnalleniyor (eğer uygunsa)</string>
@@ -76,18 +63,6 @@
<string name="account_create_new_address_book">Yeni rehber oluştur</string>
<string name="account_refresh_calendar_list">Takvim listesini yenile</string>
<string name="account_create_new_calendar">Yeni takvim oluştur</string>
<!--PermissionsActivity-->
<string name="permissions_title">DAVdroid izinleri</string>
<string name="permissions_calendar">Takvim izinleri</string>
<string name="permissions_calendar_details">Takvim (sadece olaylar)
</string>
<string name="permissions_calendar_request">Takvim izinleri iste</string>
<string name="permissions_contacts">Kişiler izinleri</string>
<string name="permissions_contacts_details">CardDAV rehberlerinin cihazınızdaki kişilerinizle senkronize edebilmek için, DAVdroid cihazınızdaki kişilerinize erişime ihtiyacı vardır.</string>
<string name="permissions_contacts_request">Kişiler izinleri iste</string>
<string name="permissions_opentasks">OpenTasks izinleri</string>
<string name="permissions_opentasks_details">CalDav iş listelerinizi yerel iş listelerinizle senkronize edebilmek için DAVdroid\'in OpenTasks\'e erişime ihtiyacı vardır.</string>
<string name="permissions_opentasks_request">OpenTasks izinleri iste</string>
<!--AddAccountActivity-->
<string name="login_title">Hesap ekle</string>
<string name="login_type_email">Eposta adresi ile giriş yap</string>
@@ -101,7 +76,6 @@
<string name="login_user_name">Kullanıcı adı</string>
<string name="login_user_name_required">Kullanıcı adı zorunludur</string>
<string name="login_base_url">Baz URL</string>
<string name="login_auth_preemptive">Önleyici doğrulama (tavsiye edilir, fakat Digest doğrulama ile uyumsuz)</string>
<string name="login_login">Giriş</string>
<string name="login_back">Geri</string>
<string name="login_create_account">Hesap yarat</string>
@@ -110,9 +84,8 @@
<string name="login_account_name_required">Hesap adı zorunludur</string>
<string name="login_account_not_created">Hesap yaratılamadı</string>
<string name="login_configuration_detection">Konfigürasyon keşfi</string>
<string name="login_querying_server">Lütfen bekle, sunucu sorgulanıyor...</string>
<string name="login_querying_server">Lütfen bekle, sunucu sorgulanıyor</string>
<string name="login_no_caldav_carddav">CalDAV veya CardDAV servisi bulunamadı.</string>
<string name="login_view_logs">Jurnallere bak</string>
<!--AccountSettingsActivity-->
<string name="settings_title">Ayarlar: %s</string>
<string name="settings_authentication">Doğrulama</string>
@@ -121,56 +94,26 @@
<string name="settings_password">Parola</string>
<string name="settings_password_summary">Parolayı sunucunuza göre güncelleyin.</string>
<string name="settings_enter_password">Parola girin:</string>
<string name="settings_preemptive">Önleyici doğrulama</string>
<string name="settings_preemptive_on">Giriş bilgileri her istek ile gönderilir (tavsiye edilir)</string>
<string name="settings_preemptive_off">Giriş bilgileri sunucu istedikten sonra gönderilir</string>
<string name="settings_sync">Senkronizasyon</string>
<string name="settings_sync_interval_contacts">Kişiler senk. aralığı</string>
<string name="settings_sync_summary_manually">Sadece elle</string>
<string name="settings_sync_summary_periodically" tools:ignore="PluralsCandidate">Her %d dakika + yerel değişikliklerde hemen</string>
<string name="settings_sync_summary_not_available">Mevcut değil</string>
<string name="settings_sync_interval_calendars">Takvimler senk. aralığı</string>
<string name="settings_sync_interval_tasks">İşler senk. aralığı</string>
<string-array name="settings_sync_interval_seconds">
<item>-1</item>
<item>300</item>
<item>600</item>
<item>900</item>
<item>3600</item>
<item>7200</item>
<item>14400</item>
<item>86400</item>
</string-array>
<string-array name="settings_sync_interval_names">
<item>Sadece elle</item>
<item>Her 5 dakikada bir</item>
<item>Her 10 dakikada bir</item>
<item>Her 15 dakikada bir</item>
<item>Her saatte bir</item>
<item>Her 2 saatte bir</item>
<item>Her 4 saatte bir</item>
<item>Günde bir</item>
</string-array>
<string name="settings_sync_wifi_only">Sadece WiFi üzerinden senkronize et</string>
<string name="settings_sync_wifi_only_on">Senkronizasyon WiFi bağlantıları ile kısıtlıdır</string>
<string name="settings_sync_wifi_only_off">Bağlantı tipi göz önünde bulundurulmaz</string>
<string name="settings_sync_wifi_only_ssid">WiFi SSID kısıtlaması</string>
<string name="settings_sync_wifi_only_ssid_on">Sadece %s üzerinden senkronize olur</string>
<string name="settings_sync_wifi_only_ssid_off">Tüm WiFi bağlantıları kullanılabilir</string>
<string name="settings_sync_wifi_only_ssid_message">Senkronizasyonu sadece bir WiFi ağına kısıtlamak için bu ağın adını (SSID) gir, veya tüm WiFi bağlantıları için boş bırak.</string>
<string name="settings_caldav">CalDAV</string>
<string name="settings_sync_time_range_past">Geçmiş olay zaman sınırı</string>
<string name="settings_sync_time_range_past_none">Tüm olaylar senkronize edilecek</string>
<plurals name="settings_sync_time_range_past_days">
<item quantity="one">%d günden daha eski olaylar göz ardı edilecektir</item>
<item quantity="other">%d günden daha eski olaylar göz ardı edilecektir</item>
</plurals>
<string name="settings_sync_time_range_past_message">Bu sayıdan daha eski olan olaylar yok sayılacaktır (0 olabilir). Tüm olayları senkronize etmek için boş bırak.</string>
<string name="settings_manage_calendar_colors">Takvim renklerini yönet</string>
<string name="settings_manage_calendar_colors_on">Takvim renkleri DAVdroid tarafından yönetilmekte</string>
<string name="settings_manage_calendar_colors_off">Takvim renkleri DAVdroid tarafından ayarlanmadı</string>
<string name="settings_version_update">DAVdroid sürüm güncellemesi</string>
<string name="settings_version_update_settings_updated">Dahili ayarlar güncellendi.</string>
<string name="settings_version_update_install_hint">Sorunlar mı var? DAVdroid\'i kaldırıp, yeniden kurun.</string>
<!--collection management-->
<string name="create_addressbook">Rehber yarat</string>
<string name="create_addressbook_display_name_hint">Benim Rehberim</string>
@@ -198,15 +141,9 @@
<string name="exception_httpexception">Bir HTTP hatası oluştu.</string>
<string name="exception_ioexception">Bir I/O hatası oluştu.</string>
<string name="exception_show_details">Detayları göster</string>
<!--sync errors and DebugInfoActivity-->
<!--sync adapters and DebugInfoActivity-->
<string name="debug_info_title">Hata ayıklama bilgisi</string>
<string name="sync_error_permissions">DAVdroid izinleri</string>
<string name="sync_error_permissions_text">Ek izinler zorunludur</string>
<string name="sync_error_calendar">Takvim senkronizasyonu başarısız (%s)</string>
<string name="sync_error_contacts">Rehber senkronizasyonu başarısız (%s)</string>
<string name="sync_error_tasks">İş senkronizasyonu başarısız (%s)</string>
<string name="sync_error">%s yaparken hata</string>
<string name="sync_error_http_dav">%s yaparken sunucu hatası</string>
<string name="sync_error_local_storage">%s yaparken veritabanı hatası</string>
<string name="sync_error_unauthorized">Kullanıcı adı/parola yanlış</string>
<!--cert4android-->
</resources>

View File

@@ -0,0 +1,242 @@
<?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="notification_channel_debugging">Зневадження</string>
<string name="notification_channel_general">Інші важливі повідомлення</string>
<string name="notification_channel_sync">Синхронізація</string>
<string name="notification_channel_sync_errors">Помилки синхронізації</string>
<string name="notification_channel_sync_io_errors">Помилка мережі та вводу/виводу</string>
<string name="notification_channel_sync_status">Повідомлення про стан</string>
<!--startup dialogs-->
<string name="startup_battery_optimization_disable">Вимкнути для DAVdroid</string>
<string name="startup_dont_show_again">Не показувати знову</string>
<string name="startup_donate">Інформація Open-Source</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 Store DRM</string>
<string name="startup_google_play_accounts_removed_message">При деяких обставинах Play Store DRM може стати причиною втрати всіх облікових записів DAVdroid після перезавантаження пристрою чи оновлення DAVdroid. Якщо ви зіткнулися із цим (і лише у цьому випадку), будь ласка, встановіть \"DAVdroid JB Workaround\" з Play Store.</string>
<string name="startup_more_info">Додаткова інформація</string>
<string name="startup_opentasks_not_installed">OpenTasks не встановлено</string>
<string name="startup_opentasks_not_installed_message">Для синхронізації завдань необхідно встановити додаток OpenTasks. (Не має потреби для контактів/подій.)</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_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_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_beta_feedback">Beta відгук</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_manual">Посібник</string>
<string name="navigation_drawer_faq">Питання/Відповіді</string>
<string name="navigation_drawer_forums">Допомога / Форуми</string>
<string name="navigation_drawer_donate">Підтримка</string>
<string name="account_list_empty">Вітаємо у DAVdroid!\n\nТепер можете додавати облікові записи CalDAV/CardDAV.</string>
<string name="accounts_global_sync_disabled">Автоматичну синхронізацію вимкнено зі сторони системи</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_carddav">CardDAV</string>
<string name="account_caldav">CalDAV</string>
<string name="account_webcal">Webcal</string>
<string name="account_synchronize_this_collection">синхронізувати дану колекцію</string>
<string name="account_read_only">лише читання</string>
<string name="account_calendar">календар</string>
<string name="account_task_list">перелік завдань</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>
<string name="account_no_webcal_handler_found">Не знайдено додатку з підтримкою Webcal</string>
<string name="account_install_icsdroid">Встановити ICSdroid</string>
<!--AddAccountActivity-->
<string name="login_title">Додати запис</string>
<string name="login_type_email">Увійти за допомогою електронної пошти</string>
<string name="login_email_address">Адреса пошти</string>
<string name="login_email_address_error">Потребує валідну електронну адресу</string>
<string name="login_password">Пароль</string>
<string name="login_password_required">Потребує пароль</string>
<string name="login_type_url">Увійти за допомогою URL та імені користувача</string>
<string name="login_url_must_be_http_or_https">URL адреса повинна починатися з http(s)://</string>
<string name="login_url_must_be_https">Посилання повинно починатися з https://</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_type_url_certificate">Вхід по посиланню та сертифікату клієнта</string>
<string name="login_select_certificate">Обрати сертифікат</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">Використовуйте вашу електронну адресу як ім\'я облікового запису, так як Android буде використовувати ім\'я облікового запису в полі ORGANIZER для подій, які ви створюватимете. Ви не можете мати два облікових записи з однаковими іменами.</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>
<!--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_certificate_alias">Прив\'язка сертифікату клієнта</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>Кожні 15 хвилин</item>
<item>Кожні 30 хвилин</item>
<item>Щогодинно</item>
<item>Кожні 2 години</item>
<item>Кожні 4 години</item>
<item>Щоденно</item>
</string-array>
<string name="settings_sync_wifi_only">Синхронізувати лише через Wi-Fi</string>
<string name="settings_sync_wifi_only_on">Виконувати синхронізацію лише через Wi-Fi</string>
<string name="settings_sync_wifi_only_off">Не враховувати тип з\'єднання</string>
<string name="settings_sync_wifi_only_ssids">Обмеження WiFi SSID</string>
<string name="settings_sync_wifi_only_ssids_on">Синхронізувати лише через %s</string>
<string name="settings_sync_wifi_only_ssids_off">Може використовуватись всі Wi-Fi з\'єднання</string>
<string name="settings_sync_wifi_only_ssids_message">Назви (SSID) дозволених Wi-Fi мереж, розділені комами (залиште порожнім для всіх)</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_contact_group_method_change">Змінити метод групування</string>
<string name="settings_contact_group_method_change_reload_contacts">Це потребує перезавантаження всіх контактів. Незбережені локальні зміни буде відхилено.</string>
<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="one">Події старші одного дня будуть проігноровані</item>
<item quantity="few">Події старші %d днів будуть проігноровані</item>
<item quantity="many">Події старші %d днів будуть проігноровані</item>
<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>
<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>
<string name="create_calendar">Створити CalDAV колекцію</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">Головна тека:</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>
<string name="collection_force_read_only">Примусово лише читання</string>
<!--ExceptionInfoFragment-->
<string name="exception">Трапилась помилка.</string>
<string name="exception_httpexception">Трапилась помилка HTTP.</string>
<string name="exception_ioexception">Трапилась помилка I/O.</string>
<string name="exception_show_details">Показати подробиці</string>
<!--sync adapters and DebugInfoActivity-->
<string name="debug_info_title">Інформація зневадження</string>
<string name="sync_contacts_read_only_address_book">Адресна книга лише для читання</string>
<plurals name="sync_contacts_local_contact_changes_discarded">
<item quantity="one">Локальну зміну контакту відхилено</item>
<item quantity="few">%d локальні зміни контакту відхилено</item>
<item quantity="many">%d локальних змін контакту відхилено</item>
<item quantity="other">%d локальних змін контакту відхилено</item>
</plurals>
<string name="sync_error_permissions">Дозволи DAVdroid</string>
<string name="sync_error_permissions_text">Потребує додаткові дозволи</string>
<string name="sync_error_opentasks_too_old">OpenTasks застарів</string>
<string name="sync_error_opentasks_required_version">Необхідна версія: %1$s (поточна %2$s)</string>
<string name="sync_error_authentication_failed">Помилка аутентифікації (перевірте обліковий запис)</string>
<string name="sync_error_io">Помилка мережі та вводу/виводу — %s</string>
<string name="sync_error_http_dav">Помилка сервера HTTP — %s</string>
<string name="sync_error_local_storage">Помилка локального сховища — %s</string>
<string name="sync_error_retry">Повторити</string>
<string name="sync_error_view_item">Перегляд елементу</string>
<!--cert4android-->
<string name="certificate_notification_connection_security">DAVdroid: Безпека з\'єднання</string>
<string name="trust_certificate_unknown_certificate_found">DAVdroid зіткнувся з невідомим сертифікатом. Чи довіряти йому?</string>
</resources>

View File

@@ -0,0 +1,17 @@
<!--
~ 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
-->
<resources>
<style name="AppThemeExt" parent="AppTheme">
<item name="android:windowActivityTransitions">true</item>
<item name="android:windowEnterTransition">@android:transition/slide_right</item>
<item name="android:windowExitTransition">@android:transition/slide_left</item>
</style>
</resources>

View File

@@ -2,33 +2,46 @@
<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="please_wait">请稍等</string>
<string name="send">发送</string>
<string name="notification_channel_debugging">调试</string>
<string name="notification_channel_general">其它重要消息</string>
<string name="notification_channel_sync">同步</string>
<string name="notification_channel_sync_errors">同步错误</string>
<string name="notification_channel_sync_io_errors">网络或 I/O 错误</string>
<string name="notification_channel_sync_status">状态消息</string>
<!--startup dialogs-->
<string name="startup_autostart_permission">自动同步</string>
<string name="startup_autostart_permission_message">%s 的系统通常会禁止自动同步。在 Android 的系统设置中手工打开自动同步即可恢复。</string>
<string name="startup_battery_optimization">定时同步</string>
<string name="startup_battery_optimization_message">你的设备会限制 DAVdroid 的同步频率,如需恢复正常同步频率,请关闭电池优化设置。</string>
<string name="startup_battery_optimization_disable">禁用电池优化</string>
<string name="startup_dont_show_again">不再显示</string>
<string name="startup_development_version">DAVdroid 预览版</string>
<string name="startup_development_version_message">这是 DAVdroid 的开发版本,部分功能可能无法正常工作。请您提出建设性反馈,帮助我们完善 DAVdroid。</string>
<string name="startup_development_version_give_feedback">反馈</string>
<string name="startup_not_now">暂不</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 商店 DRM 问题提醒</string>
<string name="startup_google_play_accounts_removed_message">部分情况下Play 商店的 DRM 可能会导致所有 DAVdroid 账户在设备重启或升级 DAVdroid 后消失。如果你遇到了该问题(并且只有这一问题),请从 Play 商店安装“DAVdroid JB Workaround”。</string>
<string name="startup_google_play_accounts_removed_more_info">更多信息</string>
<string name="startup_google_play_accounts_removed_message">某些情况下Play 商店的 DRM 可能会导致所有 DAVdroid 账户在设备重启或升级 DAVdroid 后消失。如果你遇到了该问题,请从 Play 商店安装“DAVdroid JB Workaround”,否则请不要安装修复程序</string>
<string name="startup_more_info">更多信息</string>
<string name="startup_opentasks_not_installed">OpenTasks 未安装</string>
<string name="startup_opentasks_not_installed_message">安装 OpenTasks 应用,故 DAVdroid 无法同步任务列表。</string>
<string name="startup_opentasks_not_installed_message">同步任务需安装 OpenTasks 免费应用。(如只需同步通讯录、事件,则不用安装)</string>
<string name="startup_opentasks_reinstall_davdroid">安装 OpenTasks 后,由于 Android 的限制,请重新安装 DAVdroid 并重新创建账户。</string>
<string name="startup_opentasks_not_installed_install">安装 OpenTasks</string>
<!--AboutActivity-->
<string name="about_license_terms">许可协议</string>
<string name="about_libraries">程序库</string>
<string name="about_version">版本 %1s (%2d)</string>
<string name="about_build_date">编译于 %s</string>
<string name="about_flavor_info">此版本只允许在 Google Play 上发行。</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-->
@@ -36,14 +49,18 @@
<string name="navigation_drawer_close">关闭导航抽屉</string>
<string name="navigation_drawer_subtitle">CalDAV/CardDAV 同步器</string>
<string name="navigation_drawer_about">关于 / 许可</string>
<string name="navigation_drawer_beta_feedback">测试版反馈</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_external_links">外部链接</string>
<string name="navigation_drawer_website">应用网站</string>
<string name="navigation_drawer_manual">手动</string>
<string name="navigation_drawer_faq">常见问题</string>
<string name="navigation_drawer_forums">社区</string>
<string name="navigation_drawer_forums">帮助 / 论坛</string>
<string name="navigation_drawer_donate">捐助</string>
<string name="account_list_empty">欢迎使用 DAVdroid\n\n现在你可以增加 CalDAV/CardDAV 账户。</string>
<string name="account_list_empty">欢迎使用 DAVdroid\n\n请开始增加 CalDAV/CardDAV 账户。</string>
<string name="accounts_global_sync_disabled">系统全局自动同步已禁用</string>
<string name="accounts_global_sync_enable">启用</string>
<!--DavService-->
<string name="dav_service_refresh_failed">服务配置检测失败</string>
<string name="dav_service_refresh_couldnt_refresh">无法刷新集合列表</string>
@@ -53,12 +70,19 @@
<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_reset_trusted_certificates">重设受信任证书</string>
<string name="app_settings_reset_trusted_certificates_summary">取消信任所有之前接受的证书</string>
<plurals name="app_settings_reset_trusted_certificates_success">
<item quantity="other">已删除 %d 个证书</item>
</plurals>
<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>
@@ -69,24 +93,26 @@
<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_select_collections_hint">选择需要同步的集合</string>
<string name="account_carddav">CardDAV</string>
<string name="account_caldav">CalDAV</string>
<string name="account_webcal">Webcal</string>
<string name="account_synchronize_this_collection">同步该集合</string>
<string name="account_read_only">只读</string>
<string name="account_calendar">日历</string>
<string name="account_task_list">任务列表</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>
<string name="account_no_webcal_handler_found">找不到支持 Webcal 的应用</string>
<string name="account_install_icsdroid">安装 ICSdroid</string>
<!--AddAccountActivity-->
<string name="login_title">增加账户</string>
<string name="login_type_email">使用邮箱地址登录</string>
@@ -95,12 +121,14 @@
<string name="login_password">密码</string>
<string name="login_password_required">请输入密码</string>
<string name="login_type_url">使用 URL 和用户名登录</string>
<string name="login_url_must_be_http_or_https">URL 必须以 http(s):// 为开头</string>
<string name="login_url_must_be_http_or_https">URL 以 http(s):// 为开头</string>
<string name="login_url_must_be_https">URL 需以 https:// 为开头</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">根地址</string>
<string name="login_auth_preemptive">强制认证模式(推荐使用,但不兼容 Digest 认证方式)</string>
<string name="login_type_url_certificate">使用 URL 和客户端证书登录</string>
<string name="login_select_certificate">选择证书</string>
<string name="login_login">登录</string>
<string name="login_back">返回</string>
<string name="login_create_account">创建账户</string>
@@ -110,9 +138,9 @@
<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_querying_server">正在与服务器通信,请稍等</string>
<string name="login_no_caldav_carddav">找不到 CalDAV 或 CardDAV 服务。</string>
<string name="login_view_logs">查看日志</string>
<string name="login_view_logs">显示详情</string>
<!--AccountSettingsActivity-->
<string name="settings_title">设置:%s</string>
<string name="settings_authentication">认证</string>
@@ -121,43 +149,29 @@
<string name="settings_password">密码</string>
<string name="settings_password_summary">修改服务器密码</string>
<string name="settings_enter_password">输入密码</string>
<string name="settings_preemptive">强制认证模式</string>
<string name="settings_preemptive_on">认证信息在每次请求中发送(推荐)</string>
<string name="settings_preemptive_off">认证信息在服务器要求后才发送</string>
<string name="settings_certificate_alias">客户端证书别名</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_summary_not_available">不可用</string>
<string name="settings_sync_interval_calendars">日历自动同步间隔</string>
<string name="settings_sync_interval_tasks">任务自动同步间隔</string>
<string-array name="settings_sync_interval_seconds">
<item>-1</item>
<item>300</item>
<item>600</item>
<item>900</item>
<item>3600</item>
<item>7200</item>
<item>14400</item>
<item>86400</item>
</string-array>
<string-array name="settings_sync_interval_names">
<item>手动同步</item>
<item>每 5 分钟</item>
<item>每 10 分钟</item>
<item>每 15 分钟</item>
<item>1 小时</item>
<item>30 分钟</item>
<item>每小时</item>
<item>每 2 小时</item>
<item>每 4 小时</item>
<item> 24 小时</item>
<item>天一次</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_sync_wifi_only_ssid">WiFi SSID 限制</string>
<string name="settings_sync_wifi_only_ssid_on">同步只在 %s 网络下进行</string>
<string name="settings_sync_wifi_only_ssid_off"> WiFi 网络下均会同步</string>
<string name="settings_sync_wifi_only_ssid_message">输入 WiFi 网络的名称 (SSID) ,即可限制同步只在此网络下进行。留空则不限制。</string>
<string name="settings_sync_wifi_only_ssids">WiFi SSID 限制</string>
<string name="settings_sync_wifi_only_ssids_on">只使用 %s 网络同步</string>
<string name="settings_sync_wifi_only_ssids_off"> WiFi 网络均可同步</string>
<string name="settings_sync_wifi_only_ssids_message">请用半角逗号分隔允许同步的 WiFi 网络名SSID留空则允许任意网络</string>
<string name="settings_carddav">CardDAV</string>
<string name="settings_contact_group_method">联系人分组方式</string>
<string-array name="settings_contact_group_method_values">
@@ -165,12 +179,11 @@
<item>CATEGORIES</item>
</string-array>
<string-array name="settings_contact_group_method_entries">
<item>分为不同的 VCards</item>
<item>每个联系人分类</item>
<item> VCard 文件分组</item>
<item>联系人分类分组</item>
</string-array>
<string name="settings_rfc6868_for_vcards">为 VCards 启用 RFC6868</string>
<string name="settings_rfc6868_for_vcards_on">属性值中可使用双引号</string>
<string name="settings_rfc6868_for_vcards_off">属性值中不可使用双引号</string>
<string name="settings_contact_group_method_change">修改分组方式</string>
<string name="settings_contact_group_method_change_reload_contacts">本次操作需要重新载入所有联系人,未同步的本地修改会被撤销。</string>
<string name="settings_caldav">CalDAV</string>
<string name="settings_sync_time_range_past">旧日程时间限制</string>
<string name="settings_sync_time_range_past_none">同步所有日程</string>
@@ -181,9 +194,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_version_update">DAVdroid 版本升级</string>
<string name="settings_version_update_settings_updated">应用设置已更新。</string>
<string name="settings_version_update_install_hint">出现问题了?请卸载 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>
@@ -205,34 +219,32 @@
<string name="delete_collection_confirm_title">你确定吗?</string>
<string name="delete_collection_confirm_warning">这个集合 %s 及其所有数据将会从服务器删除。</string>
<string name="delete_collection_deleting_collection">正在删除集合</string>
<string name="collection_force_read_only">强制只读</string>
<string name="collection_properties">属性</string>
<string name="collection_properties_url">地址 (URL):</string>
<string name="collection_properties_copy_url">复制 URL</string>
<!--ExceptionInfoFragment-->
<string name="exception">出现错误</string>
<string name="exception_httpexception">出现 HTTP 错误</string>
<string name="exception_ioexception">出现 I/O 错误</string>
<string name="exception_show_details">显示详情</string>
<!--sync errors and DebugInfoActivity-->
<!--sync adapters and DebugInfoActivity-->
<string name="debug_info_title">调试信息</string>
<string name="sync_contacts_read_only_address_book">只读通讯录</string>
<plurals name="sync_contacts_local_contact_changes_discarded">
<item quantity="other">%d 本地联系人修改被撤销</item>
</plurals>
<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>
<string name="sync_error_opentasks_too_old">OpenTasks 版本太旧</string>
<string name="sync_error_opentasks_required_version">最低版本 %1$s (当前 %2$s</string>
<string name="sync_error_authentication_failed">认证失败(请检查登录凭据,如用户名密码</string>
<string name="sync_error_io">网络或 I/O 错误 %s</string>
<string name="sync_error_http_dav">HTTP 服务器错误 %s</string>
<string name="sync_error_local_storage">本地存储错误 %s</string>
<string name="sync_error_retry">重试</string>
<string name="sync_error_view_item">显示项目</string>
<!--cert4android-->
<string name="certificate_notification_connection_security">DAVdroid: 连接安全性</string>
<string name="trust_certificate_unknown_certificate_found">DAVdroid 遇到了未知证书。你是否要信任该证书?</string>
</resources>

View File

@@ -0,0 +1,179 @@
<?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>
<!--startup dialogs-->
<string name="startup_battery_optimization_disable">關閉 DAVdroid 的電池最佳化</string>
<string name="startup_dont_show_again">不要再顯示此訊息</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_opentasks_not_installed">OpenTasks 未安裝</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_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_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">新聞 &amp; 更新</string>
<string name="navigation_drawer_external_links">外部連結</string>
<string name="navigation_drawer_website">我們的網站</string>
<string name="navigation_drawer_faq">常見問答</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>
<!--AddAccountActivity-->
<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>
<!--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 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 adapters and DebugInfoActivity-->
<string name="debug_info_title">除錯訊息</string>
<string name="sync_error_permissions">DAVdroid 權限</string>
<string name="sync_error_permissions_text">需要額外的權限</string>
<!--cert4android-->
<string name="certificate_notification_connection_security">DAVdroid: 連線安全性</string>
<string name="trust_certificate_unknown_certificate_found">DAVdroid 發現未知的憑證,您要信任它嗎?</string>
</resources>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright © 2013 2016 Ricki Hirner (bitfire web engineering).
~ 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
@@ -14,6 +14,13 @@
android:id="@+id/nav_about"
android:icon="@drawable/ic_info_dark"
android:title="@string/navigation_drawer_about"/>
<item
android:id="@+id/nav_beta_feedback"
android:icon="@drawable/ic_forum_dark"
android:title="@string/navigation_drawer_beta_feedback"
android:visible="false"/>
<item
android:id="@+id/nav_app_settings"
android:icon="@drawable/ic_settings_dark"
@@ -35,6 +42,10 @@
android:id="@+id/nav_website"
android:icon="@drawable/ic_home_dark"
android:title="@string/navigation_drawer_website"/>
<item
android:id="@+id/nav_manual"
android:icon="@drawable/ic_info_dark"
android:title="@string/navigation_drawer_manual"/>
<item
android:id="@+id/nav_faq"
android:icon="@drawable/ic_help_dark"
@@ -46,9 +57,8 @@
<item
android:id="@+id/nav_donate"
android:icon="@drawable/ic_attach_money_dark"
android:title="(entry disabled)"
android:visible="false"
tools:ignore="HardcodedText"/>
android:title="@string/navigation_drawer_donate"
android:visible="false"/>
</menu>
</item>

View File

@@ -15,28 +15,22 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS"/>
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS"/>
<uses-permission android:name="android.permission.READ_SYNC_STATS"/>
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS"/>
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
<!-- account management permissions not required for own accounts since API level 22 -->
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" android:maxSdkVersion="22"/>
<uses-permission android:name="android.permission.GET_ACCOUNTS" android:maxSdkVersion="22"/>
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" android:maxSdkVersion="22"/>
<!-- legacy permissions -->
<uses-permission
android:name="android.permission.AUTHENTICATE_ACCOUNTS"
android:maxSdkVersion="22"
tools:ignore="UnusedAttribute"/>
<!--
for writing external log files; permission only required for SDK <= 18 because since then,
writing to app-private directory doesn't require extra permissions
-->
<uses-permission
android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="18"
tools:ignore="UnusedAttribute"/>
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="18"
tools:ignore="UnusedAttribute"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="18"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="18"/>
<!-- other permissions -->
<!-- android.permission-group.CONTACTS -->
@@ -46,34 +40,82 @@
<uses-permission android:name="android.permission.READ_CALENDAR"/>
<uses-permission android:name="android.permission.WRITE_CALENDAR"/>
<!-- android.permission-group.LOCATION -->
<!-- required since Android 8.1 to get the WiFi name (for "sync in Wifi only" feature) -->
<uses-permission-sdk-23 android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<!-- ical4android declares task access permissions -->
<application
android:name=".App"
android:allowBackup="true"
android:fullBackupContent="false"
android:icon="@drawable/ic_launcher"
android:networkSecurityConfig="@xml/network_security_config"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme"
android:theme="@style/AppThemeExt"
tools:ignore="UnusedAttribute">
<receiver
android:name=".App$ReinitLoggingReceiver"
android:exported="false"
android:process=":sync">
<intent-filter>
<action android:name="at.bitfire.davdroid.REINIT_LOGGER"/>
</intent-filter>
</receiver>
<receiver
android:name=".AccountSettings$AppUpdatedReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.PACKAGE_REPLACED" />
<data android:scheme="package" android:path="at.bitfire.davdroid" />
</intent-filter>
</receiver>
<service android:name=".DavService"/>
<service android:name=".settings.Settings"/>
<activity
android:name=".ui.AccountsActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity
android:name=".ui.AboutActivity"
android:label="@string/navigation_drawer_about"
android:theme="@style/AppTheme.NoActionBar"
android:parentActivityName=".ui.AccountsActivity"/>
<activity
android:name=".ui.AppSettingsActivity"
android:label="@string/app_settings"
android:parentActivityName=".ui.AccountsActivity"/>
<activity
android:name=".ui.setup.LoginActivity"
android:label="@string/login_title"
android:parentActivityName=".ui.AccountsActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
</intent-filter>
</activity>
<activity
android:name=".ui.AccountActivity"
android:parentActivityName=".ui.AccountsActivity">
</activity>
<activity android:name=".ui.AccountSettingsActivity"/>
<activity android:name=".ui.CreateAddressBookActivity"
android:label="@string/create_addressbook"/>
<activity android:name=".ui.CreateCalendarActivity"
android:label="@string/create_calendar"/>
<activity
android:name=".ui.DebugInfoActivity"
android:parentActivityName=".ui.AppSettingsActivity"
android:exported="true"
android:label="@string/debug_info_title">
</activity>
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="@string/authority_log_provider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/log_paths" />
</provider>
<!-- account type "DAVdroid" -->
<service
android:name=".syncadapter.AccountAuthenticatorService"
android:exported="false">
@@ -85,22 +127,6 @@
android:name="android.accounts.AccountAuthenticator"
android:resource="@xml/account_authenticator"/>
</service>
<service
android:name=".syncadapter.ContactsSyncAdapterService"
android:exported="true"
android:process=":sync"
tools:ignore="ExportedService">
<intent-filter>
<action android:name="android.content.SyncAdapter"/>
</intent-filter>
<meta-data
android:name="android.content.SyncAdapter"
android:resource="@xml/sync_contacts"/>
<meta-data
android:name="android.provider.CONTACTS_STRUCTURE"
android:resource="@xml/contacts"/>
</service>
<service
android:name=".syncadapter.CalendarsSyncAdapterService"
android:exported="true"
@@ -128,73 +154,53 @@
android:resource="@xml/sync_tasks"/>
</service>
<!-- account type "DAVdroid Address book" -->
<service
android:name=".DavService"
android:enabled="true">
android:name=".syncadapter.NullAuthenticatorService"
android:exported="false">
<intent-filter>
<action android:name="android.accounts.AccountAuthenticator"/>
</intent-filter>
<meta-data
android:name="android.accounts.AccountAuthenticator"
android:resource="@xml/account_authenticator_address_book"/>
</service>
<receiver
android:name=".AccountsChangedReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.accounts.LOGIN_ACCOUNTS_CHANGED"/>
</intent-filter>
</receiver>
<activity
android:name=".ui.AccountsActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity
android:name=".ui.AboutActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar"
android:parentActivityName=".ui.AccountsActivity"/>
<activity
android:name=".ui.AppSettingsActivity"
android:label="@string/app_settings"
android:parentActivityName=".ui.AccountsActivity"/>
<activity android:name=".ui.PermissionsActivity"
android:label="@string/permissions_title"
android:parentActivityName=".ui.AccountsActivity"/>
<activity
android:name=".ui.setup.LoginActivity"
android:label="@string/login_title"
android:parentActivityName=".ui.AccountsActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
</intent-filter>
</activity>
<activity
android:name=".ui.AccountActivity"
android:parentActivityName=".ui.AccountsActivity">
</activity>
<activity android:name=".ui.AccountSettingsActivity"/>
<activity android:name=".ui.CreateAddressBookActivity"
android:label="@string/create_addressbook"/>
<activity android:name=".ui.CreateCalendarActivity"
android:label="@string/create_calendar"/>
<activity
android:name=".ui.DebugInfoActivity"
<provider
android:authorities="@string/address_books_authority"
android:exported="false"
android:label="@string/address_books_authority_title"
android:name=".syncadapter.AddressBookProvider"
android:multiprocess="false"/>
<service
android:name=".syncadapter.AddressBooksSyncAdapterService"
android:exported="true"
android:label="@string/debug_info_title">
</activity>
android:process=":sync"
tools:ignore="ExportedService">
<intent-filter>
<action android:name="android.content.SyncAdapter"/>
</intent-filter>
<!-- MemorizingTrustManager -->
<activity
android:name="de.duenndns.ssl.MemorizingActivity"
android:theme="@android:style/Theme.Holo.Light.Dialog.NoActionBar"/>
<meta-data
android:name="android.content.SyncAdapter"
android:resource="@xml/sync_address_books"/>
</service>
<service
android:name=".syncadapter.ContactsSyncAdapterService"
android:exported="true"
android:process=":sync"
tools:ignore="ExportedService">
<intent-filter>
<action android:name="android.content.SyncAdapter"/>
</intent-filter>
<meta-data
android:name="android.content.SyncAdapter"
android:resource="@xml/sync_contacts"/>
<meta-data
android:name="android.provider.CONTACTS_STRUCTURE"
android:resource="@xml/contacts"/>
</service>
</application>

View File

@@ -0,0 +1,28 @@
package at.bitfire.davdroid.settings;
import at.bitfire.davdroid.settings.ISettingsObserver;
interface ISettings {
void forceReload();
boolean has(String key);
boolean getBoolean(String key, boolean defaultValue);
int getInt(String key, int defaultValue);
long getLong(String key, long defaultValue);
String getString(String key, String defaultValue);
boolean isWritable(String key);
boolean putBoolean(String key, boolean value);
boolean putInt(String key, int value);
boolean putLong(String key, long value);
boolean putString(String key, String value);
boolean remove(String key);
void registerObserver(ISettingsObserver observer);
void unregisterObserver(ISettingsObserver observer);
}

View File

@@ -0,0 +1,7 @@
package at.bitfire.davdroid.settings;
interface ISettingsObserver {
void onSettingsChanged();
}

View File

@@ -1,153 +0,0 @@
<h3>Apache License, Version 2.0, January 2004</h3>
<p><a href="http://www.apache.org/licenses/">http://www.apache.org/licenses/</a> </p>
<p>TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION</p>
<p><strong><a name="definitions">1. Definitions</a></strong>.</p>
<p>"License" shall mean the terms and conditions for use, reproduction, and
distribution as defined by Sections 1 through 9 of this document.</p>
<p>"Licensor" shall mean the copyright owner or entity authorized by the
copyright owner that is granting the License.</p>
<p>"Legal Entity" shall mean the union of the acting entity and all other
entities that control, are controlled by, or are under common control with
that entity. For the purposes of this definition, "control" means (i) the
power, direct or indirect, to cause the direction or management of such
entity, whether by contract or otherwise, or (ii) ownership of fifty
percent (50%) or more of the outstanding shares, or (iii) beneficial
ownership of such entity.</p>
<p>"You" (or "Your") shall mean an individual or Legal Entity exercising
permissions granted by this License.</p>
<p>"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation source,
and configuration files.</p>
<p>"Object" form shall mean any form resulting from mechanical transformation
or translation of a Source form, including but not limited to compiled
object code, generated documentation, and conversions to other media types.</p>
<p>"Work" shall mean the work of authorship, whether in Source or Object form,
made available under the License, as indicated by a copyright notice that
is included in or attached to the work (an example is provided in the
Appendix below).</p>
<p>"Derivative Works" shall mean any work, whether in Source or Object form,
that is based on (or derived from) the Work and for which the editorial
revisions, annotations, elaborations, or other modifications represent, as
a whole, an original work of authorship. For the purposes of this License,
Derivative Works shall not include works that remain separable from, or
merely link (or bind by name) to the interfaces of, the Work and Derivative
Works thereof.</p>
<p>"Contribution" shall mean any work of authorship, including the original
version of the Work and any modifications or additions to that Work or
Derivative Works thereof, that is intentionally submitted to Licensor for
inclusion in the Work by the copyright owner or by an individual or Legal
Entity authorized to submit on behalf of the copyright owner. For the
purposes of this definition, "submitted" means any form of electronic,
verbal, or written communication sent to the Licensor or its
representatives, including but not limited to communication on electronic
mailing lists, source code control systems, and issue tracking systems that
are managed by, or on behalf of, the Licensor for the purpose of discussing
and improving the Work, but excluding communication that is conspicuously
marked or otherwise designated in writing by the copyright owner as "Not a
Contribution."</p>
<p>"Contributor" shall mean Licensor and any individual or Legal Entity on
behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.</p>
<p><strong><a name="copyright">2. Grant of Copyright License</a></strong>. Subject to the
terms and conditions of this License, each Contributor hereby grants to You
a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of, publicly
display, publicly perform, sublicense, and distribute the Work and such
Derivative Works in Source or Object form.</p>
<p><strong><a name="patent">3. Grant of Patent License</a></strong>. Subject to the terms
and conditions of this License, each Contributor hereby grants to You a
perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made, use,
offer to sell, sell, import, and otherwise transfer the Work, where such
license applies only to those patent claims licensable by such Contributor
that are necessarily infringed by their Contribution(s) alone or by
combination of their Contribution(s) with the Work to which such
Contribution(s) was submitted. If You institute patent litigation against
any entity (including a cross-claim or counterclaim in a lawsuit) alleging
that the Work or a Contribution incorporated within the Work constitutes
direct or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate as of the
date such litigation is filed.</p>
<p><strong><a name="redistribution">4. Redistribution</a></strong>. You may reproduce and
distribute copies of the Work or Derivative Works thereof in any medium,
with or without modifications, and in Source or Object form, provided that
You meet the following conditions:</p>
<p>a. You must give any other recipients of the Work or Derivative Works a
copy of this License; and</p>
<p>b. You must cause any modified files to carry prominent notices stating
that You changed the files; and</p>
<p>c. You must retain, in the Source form of any Derivative Works that You
distribute, all copyright, patent, trademark, and attribution notices from
the Source form of the Work, excluding those notices that do not pertain to
any part of the Derivative Works; and</p>
<p>d. If the Work includes a "NOTICE" text file as part of its distribution,
then any Derivative Works that You distribute must include a readable copy
of the attribution notices contained within such NOTICE file, excluding
those notices that do not pertain to any part of the Derivative Works, in
at least one of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or documentation,
if provided along with the Derivative Works; or, within a display generated
by the Derivative Works, if and wherever such third-party notices normally
appear. The contents of the NOTICE file are for informational purposes only
and do not modify the License. You may add Your own attribution notices
within Derivative Works that You distribute, alongside or as an addendum to
the NOTICE text from the Work, provided that such additional attribution
notices cannot be construed as modifying the License.
<br/>
<br/>
You may add Your own copyright statement to Your modifications and may
provide additional or different license terms and conditions for use,
reproduction, or distribution of Your modifications, or for any such
Derivative Works as a whole, provided Your use, reproduction, and
distribution of the Work otherwise complies with the conditions stated in
this License.
</p>
<p><strong><a name="contributions">5. Submission of Contributions</a></strong>. Unless You
explicitly state otherwise, any Contribution intentionally submitted for
inclusion in the Work by You to the Licensor shall be under the terms and
conditions of this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify the
terms of any separate license agreement you may have executed with Licensor
regarding such Contributions.</p>
<p><strong><a name="trademarks">6. Trademarks</a></strong>. This License does not grant
permission to use the trade names, trademarks, service marks, or product
names of the Licensor, except as required for reasonable and customary use
in describing the origin of the Work and reproducing the content of the
NOTICE file.</p>
<p><strong><a name="no-warranty">7. Disclaimer of Warranty</a></strong>. Unless required by
applicable law or agreed to in writing, Licensor provides the Work (and
each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including,
without limitation, any warranties or conditions of TITLE,
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You
are solely responsible for determining the appropriateness of using or
redistributing the Work and assume any risks associated with Your exercise
of permissions under this License.</p>
<p><strong><a name="no-liability">8. Limitation of Liability</a></strong>. In no event and
under no legal theory, whether in tort (including negligence), contract, or
otherwise, unless required by applicable law (such as deliberate and
grossly negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a result
of this License or out of the use or inability to use the Work (including
but not limited to damages for loss of goodwill, work stoppage, computer
failure or malfunction, or any and all other commercial damages or losses),
even if such Contributor has been advised of the possibility of such
damages.</p>
<p><strong><a name="additional">9. Accepting Warranty or Additional Liability</a></strong>.
While redistributing the Work or Derivative Works thereof, You may choose
to offer, and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this License.
However, in accepting such obligations, You may act only on Your own behalf
and on Your sole responsibility, not on behalf of any other Contributor,
and only if You agree to indemnify, defend, and hold each Contributor
harmless for any liability incurred by, or claims asserted against, such
Contributor by reason of your accepting any such warranty or additional
liability.</p>
<p>END OF TERMS AND CONDITIONS</p>

View File

@@ -1,28 +0,0 @@
<h3>BSD License (3-clause)</h3>
<p>Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:</p>
<p>o Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.</p>
<p>o Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.</p>
<p>o Neither the name of Ben Fortuna nor the names of any other contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.</p>
<p>THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</p>

View File

@@ -1,23 +0,0 @@
<h3>BSD License</h3>
<p>Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:</p>
<p>1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.</p>
<p>2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.</p>
<p>THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</p>

View File

@@ -2,9 +2,9 @@
<p style="text-align: center;">Version 3, 29 June 2007</p>
<p>Copyright &copy; 2007 Free Software Foundation, Inc.
&lt;<a href="http://fsf.org/">http://fsf.org/</a>&gt;</p><p>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.</p>
&lt;<a href="http://fsf.org/">http://fsf.org/</a>&gt;</p><p>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.</p>
<h3><a name="preamble"></a>Preamble</h3>
@@ -42,16 +42,16 @@ know their rights.</p>
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.</p>
<p>For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
<p>For the developers\' and authors\' protection, the GPL clearly explains
that there is no warranty for this free software. For both users\' and
authors\' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.</p>
<p>Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
protecting users\' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
@@ -77,7 +77,7 @@ modification follow.</p>
<p>&ldquo;Copyright&rdquo; also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.</p>
<p>&ldquo;The Program&rdquo; refers to any copyrightable work licensed under this
License. Each licensee is addressed as &ldquo;you&rdquo;. &ldquo;Licensees&rdquo; and
&ldquo;recipients&rdquo; may be individuals or organizations.</p>
@@ -135,7 +135,7 @@ produce the work, or an object code interpreter used to run it.</p>
<p>The &ldquo;Corresponding Source&rdquo; for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
control those activities. However, it does not include the work\'s
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
@@ -177,7 +177,7 @@ your copyrighted material outside their relationship with you.</p>
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.</p>
<h4><a name="section3"></a>3. Protecting Users' Legal Rights From Anti-Circumvention Law.</h4>
<h4><a name="section3"></a>3. Protecting Users\' Legal Rights From Anti-Circumvention Law.</h4>
<p>No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
@@ -189,13 +189,13 @@ measures.</p>
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
modification of the work as a means of enforcing, against the work\'s
users, your or third parties\' legal rights to forbid circumvention of
technological measures.</p>
<h4><a name="section4"></a>4. Conveying Verbatim Copies.</h4>
<p>You may convey verbatim copies of the Program's source code as you
<p>You may convey verbatim copies of the Program\'s source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
@@ -240,7 +240,7 @@ works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
&ldquo;aggregate&rdquo; if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
used to limit the access or legal rights of the compilation\'s users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.</p>
@@ -462,7 +462,7 @@ organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
licenses to the work the party\'s predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.</p>
@@ -479,9 +479,9 @@ sale, or importing the Program or any portion of it.</p>
<p>A &ldquo;contributor&rdquo; is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's &ldquo;contributor version&rdquo;.</p>
work thus licensed is called the contributor\'s &ldquo;contributor version&rdquo;.</p>
<p>A contributor's &ldquo;essential patent claims&rdquo; are all patent claims
<p>A contributor\'s &ldquo;essential patent claims&rdquo; are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
@@ -492,7 +492,7 @@ patent sublicenses in a manner consistent with the requirements of
this License.</p>
<p>Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
patent license under the contributor\'s essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.</p>
@@ -513,10 +513,10 @@ patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. &ldquo;Knowingly relying&rdquo; means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
covered work in a country, or your recipient\'s use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.</p>
<p>If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
@@ -544,7 +544,7 @@ or that patent license was granted, prior to 28 March 2007.</p>
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.</p>
<h4><a name="section12"></a>12. No Surrender of Others' Freedom.</h4>
<h4><a name="section12"></a>12. No Surrender of Others\' Freedom.</h4>
<p>If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
@@ -584,7 +584,7 @@ GNU General Public License, you may choose any version ever published
by the Free Software Foundation.</p>
<p>If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
versions of the GNU General Public License can be used, that proxy\'s
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.</p>

View File

@@ -1,7 +0,0 @@
<h3>The MIT License (MIT)</h3>
<p>Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:</p>
<p>The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.</p>
<p>THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.</p>

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@@ -1,464 +0,0 @@
/*
* Copyright © 2013 2015 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.accounts.Account;
import android.accounts.AccountManager;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.PeriodicSync;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.provider.CalendarContract;
import android.provider.ContactsContract;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.app.NotificationCompat;
import android.text.TextUtils;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import at.bitfire.davdroid.model.ServiceDB;
import at.bitfire.davdroid.model.ServiceDB.Collections;
import at.bitfire.davdroid.model.ServiceDB.HomeSets;
import at.bitfire.davdroid.model.ServiceDB.Services;
import at.bitfire.davdroid.resource.LocalAddressBook;
import at.bitfire.davdroid.resource.LocalCalendar;
import at.bitfire.davdroid.resource.LocalTaskList;
import at.bitfire.ical4android.CalendarStorageException;
import at.bitfire.ical4android.TaskProvider;
import at.bitfire.vcard4android.ContactsStorageException;
import at.bitfire.vcard4android.GroupMethod;
import lombok.Cleanup;
import okhttp3.HttpUrl;
public class AccountSettings {
private final static int CURRENT_VERSION = 4;
private final static String
KEY_SETTINGS_VERSION = "version",
KEY_USERNAME = "user_name",
KEY_AUTH_PREEMPTIVE = "auth_preemptive",
KEY_WIFI_ONLY = "wifi_only", // sync on WiFi only (default: false)
KEY_WIFI_ONLY_SSID = "wifi_only_ssid"; // restrict sync to specific WiFi SSID
/** Whether to use RFC 6868 for VCards
* value = null (not existing) use RFC6868-style encoding (default value)
* "0" don't use RFC 6868-style encoding
*/
private final static String KEY_VCARD_RFC6868 = "vcard_rfc6868";
/** Time range limitation to the past [in days]
value = null default value (DEFAULT_TIME_RANGE_PAST_DAYS)
< 0 (-1) no limit
>= 0 entries more than n days in the past won't be synchronized
*/
private final static String KEY_TIME_RANGE_PAST_DAYS = "time_range_past_days";
private final static int DEFAULT_TIME_RANGE_PAST_DAYS = 90;
/* Whether DAVdroid sets the local calendar color to the value from service DB at every sync
value = null (not existing) true (default)
"0" false */
private final static String KEY_MANAGE_CALENDAR_COLORS = "manage_calendar_colors";
/** Contact group method:
value = null (not existing) groups as separate VCards (default)
"CATEGORIES" groups are per-contact CATEGORIES
*/
private final static String KEY_CONTACT_GROUP_METHOD = "contact_group_method";
public final static long SYNC_INTERVAL_MANUALLY = -1;
final Context context;
final AccountManager accountManager;
final Account account;
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public AccountSettings(@NonNull Context context, @NonNull Account account) throws InvalidAccountException {
this.context = context;
this.account = account;
accountManager = AccountManager.get(context);
synchronized(AccountSettings.class) {
String versionStr = accountManager.getUserData(account, KEY_SETTINGS_VERSION);
if (versionStr == null)
throw new InvalidAccountException(account);
int version = 0;
try {
version = Integer.parseInt(versionStr);
} catch (NumberFormatException ignored) {
}
App.log.info("Account " + account.name + " has version " + version + ", current version: " + CURRENT_VERSION);
if (version < CURRENT_VERSION) {
Bitmap bitmapLogo = null;
Drawable drawableLogo = android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP ?
context.getDrawable(R.drawable.ic_launcher) :
context.getResources().getDrawable(R.drawable.ic_launcher);
if (drawableLogo instanceof BitmapDrawable)
bitmapLogo = ((BitmapDrawable)drawableLogo).getBitmap();
Notification notify = new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.ic_new_releases_light)
.setLargeIcon(bitmapLogo)
.setContentTitle(context.getString(R.string.settings_version_update))
.setContentText(context.getString(R.string.settings_version_update_settings_updated))
.setSubText(context.getString(R.string.settings_version_update_install_hint))
.setStyle(new NotificationCompat.BigTextStyle()
.bigText(context.getString(R.string.settings_version_update_settings_updated)))
.setCategory(NotificationCompat.CATEGORY_SYSTEM)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setContentIntent(PendingIntent.getActivity(context, 0,
new Intent(Intent.ACTION_VIEW, Constants.webUri.buildUpon().appendEncodedPath("faq/entry/davdroid-not-working-after-update/").build()),
PendingIntent.FLAG_CANCEL_CURRENT))
.setLocalOnly(true)
.build();
NotificationManager nm = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
nm.notify(Constants.NOTIFICATION_ACCOUNT_SETTINGS_UPDATED, notify);
update(version);
}
}
}
public static Bundle initialUserData(String userName, boolean preemptive) {
Bundle bundle = new Bundle();
bundle.putString(KEY_SETTINGS_VERSION, String.valueOf(CURRENT_VERSION));
bundle.putString(KEY_USERNAME, userName);
bundle.putString(KEY_AUTH_PREEMPTIVE, Boolean.toString(preemptive));
return bundle;
}
// authentication settings
public String username() { return accountManager.getUserData(account, KEY_USERNAME); }
public void username(@NonNull String userName) { accountManager.setUserData(account, KEY_USERNAME, userName); }
public String password() { return accountManager.getPassword(account); }
public void password(@NonNull String password) { accountManager.setPassword(account, password); }
public boolean preemptiveAuth() { return Boolean.parseBoolean(accountManager.getUserData(account, KEY_AUTH_PREEMPTIVE)); }
public void preemptiveAuth(boolean preemptive) { accountManager.setUserData(account, KEY_AUTH_PREEMPTIVE, Boolean.toString(preemptive)); }
// sync. settings
public Long getSyncInterval(@NonNull String authority) {
if (ContentResolver.getIsSyncable(account, authority) <= 0)
return null;
if (ContentResolver.getSyncAutomatically(account, authority)) {
List<PeriodicSync> syncs = ContentResolver.getPeriodicSyncs(account, authority);
if (syncs.isEmpty())
return SYNC_INTERVAL_MANUALLY;
else
return syncs.get(0).period;
} else
return SYNC_INTERVAL_MANUALLY;
}
public void setSyncInterval(@NonNull String authority, long seconds) {
if (seconds == SYNC_INTERVAL_MANUALLY) {
ContentResolver.setSyncAutomatically(account, authority, false);
} else {
ContentResolver.setSyncAutomatically(account, authority, true);
ContentResolver.addPeriodicSync(account, authority, new Bundle(), seconds);
}
}
public boolean getSyncWifiOnly() {
return accountManager.getUserData(account, KEY_WIFI_ONLY) != null;
}
public void setSyncWiFiOnly(boolean wiFiOnly) {
accountManager.setUserData(account, KEY_WIFI_ONLY, wiFiOnly ? "1" : null);
}
@Nullable
public String getSyncWifiOnlySSID() {
return accountManager.getUserData(account, KEY_WIFI_ONLY_SSID);
}
public void setSyncWifiOnlySSID(String ssid) {
accountManager.setUserData(account, KEY_WIFI_ONLY_SSID, ssid);
}
// CardDAV settings
public boolean getVCardRFC6868() {
return accountManager.getUserData(account, KEY_VCARD_RFC6868) == null;
}
public void setVCardRFC6868(boolean use) {
accountManager.setUserData(account, KEY_VCARD_RFC6868, use ? null : "0");
}
// CalDAV settings
@Nullable
public Integer getTimeRangePastDays() {
String strDays = accountManager.getUserData(account, KEY_TIME_RANGE_PAST_DAYS);
if (strDays != null) {
int days = Integer.valueOf(strDays);
return days < 0 ? null : days;
} else
return DEFAULT_TIME_RANGE_PAST_DAYS;
}
public void setTimeRangePastDays(@Nullable Integer days) {
accountManager.setUserData(account, KEY_TIME_RANGE_PAST_DAYS, String.valueOf(days == null ? -1 : days));
}
public boolean getManageCalendarColors() {
return accountManager.getUserData(account, KEY_MANAGE_CALENDAR_COLORS) == null;
}
public void setManageCalendarColors(boolean manage) {
accountManager.setUserData(account, KEY_MANAGE_CALENDAR_COLORS, manage ? null : "0");
}
// CardDAV settings
@NonNull
public GroupMethod getGroupMethod() {
final String name = accountManager.getUserData(account, KEY_CONTACT_GROUP_METHOD);
return name != null ?
GroupMethod.valueOf(name) :
GroupMethod.GROUP_VCARDS;
}
public void setGroupMethod(@NonNull GroupMethod method) {
final String name = method == GroupMethod.GROUP_VCARDS ? null : method.name();
accountManager.setUserData(account, KEY_CONTACT_GROUP_METHOD, name);
}
// update from previous account settings
private void update(int fromVersion) {
for (int toVersion = fromVersion + 1; toVersion <= CURRENT_VERSION; toVersion++) {
App.log.info("Updating account " + account.name + " from version " + fromVersion + " to " + toVersion);
try {
Method updateProc = getClass().getDeclaredMethod("update_" + fromVersion + "_" + toVersion);
updateProc.invoke(this);
accountManager.setUserData(account, KEY_SETTINGS_VERSION, String.valueOf(toVersion));
} catch (Exception e) {
App.log.log(Level.SEVERE, "Couldn't update account settings", e);
}
fromVersion = toVersion;
}
}
@SuppressWarnings({ "Recycle", "unused" })
private void update_1_2() throws ContactsStorageException {
/* - KEY_ADDRESSBOOK_URL ("addressbook_url"),
- KEY_ADDRESSBOOK_CTAG ("addressbook_ctag"),
- KEY_ADDRESSBOOK_VCARD_VERSION ("addressbook_vcard_version") are not used anymore (now stored in ContactsContract.SyncState)
- KEY_LAST_ANDROID_VERSION ("last_android_version") has been added
*/
// move previous address book info to ContactsContract.SyncState
@Cleanup("release") ContentProviderClient provider = context.getContentResolver().acquireContentProviderClient(ContactsContract.AUTHORITY);
if (provider == null)
throw new ContactsStorageException("Couldn't access Contacts provider");
LocalAddressBook addr = new LocalAddressBook(account, provider);
// until now, ContactsContract.Settings.UNGROUPED_VISIBLE was not set explicitly
ContentValues values = new ContentValues();
values.put(ContactsContract.Settings.UNGROUPED_VISIBLE, 1);
addr.updateSettings(values);
String url = accountManager.getUserData(account, "addressbook_url");
if (!TextUtils.isEmpty(url))
addr.setURL(url);
accountManager.setUserData(account, "addressbook_url", null);
String cTag = accountManager.getUserData(account, "addressbook_ctag");
if (!TextUtils.isEmpty(cTag))
addr.setCTag(cTag);
accountManager.setUserData(account, "addressbook_ctag", null);
}
@SuppressWarnings({ "Recycle", "unused" })
private void update_2_3() {
// Don't show a warning for Android updates anymore
accountManager.setUserData(account, "last_android_version", null);
Long serviceCardDAV = null, serviceCalDAV = null;
ServiceDB.OpenHelper dbHelper = new ServiceDB.OpenHelper(context);
try {
SQLiteDatabase db = dbHelper.getWritableDatabase();
// we have to create the WebDAV Service database only from the old address book, calendar and task list URLs
// CardDAV: migrate address books
ContentProviderClient client = context.getContentResolver().acquireContentProviderClient(ContactsContract.AUTHORITY);
if (client != null)
try {
LocalAddressBook addrBook = new LocalAddressBook(account, client);
String url = addrBook.getURL();
if (url != null) {
App.log.fine("Migrating address book " + url);
// insert CardDAV service
ContentValues values = new ContentValues();
values.put(Services.ACCOUNT_NAME, account.name);
values.put(Services.SERVICE, Services.SERVICE_CARDDAV);
serviceCardDAV = db.insert(Services._TABLE, null, values);
// insert address book
values.clear();
values.put(Collections.SERVICE_ID, serviceCardDAV);
values.put(Collections.URL, url);
values.put(Collections.SYNC, 1);
db.insert(Collections._TABLE, null, values);
// insert home set
HttpUrl homeSet = HttpUrl.parse(url).resolve("../");
values.clear();
values.put(HomeSets.SERVICE_ID, serviceCardDAV);
values.put(HomeSets.URL, homeSet.toString());
db.insert(HomeSets._TABLE, null, values);
}
} catch (ContactsStorageException e) {
App.log.log(Level.SEVERE, "Couldn't migrate address book", e);
} finally {
client.release();
}
// CalDAV: migrate calendars + task lists
Set<String> collections = new HashSet<>();
Set<HttpUrl> homeSets = new HashSet<>();
client = context.getContentResolver().acquireContentProviderClient(CalendarContract.AUTHORITY);
if (client != null)
try {
LocalCalendar calendars[] = (LocalCalendar[])LocalCalendar.find(account, client, LocalCalendar.Factory.INSTANCE, null, null);
for (LocalCalendar calendar : calendars) {
String url = calendar.getName();
App.log.fine("Migrating calendar " + url);
collections.add(url);
homeSets.add(HttpUrl.parse(url).resolve("../"));
}
} catch (CalendarStorageException e) {
App.log.log(Level.SEVERE, "Couldn't migrate calendars", e);
} finally {
client.release();
}
TaskProvider provider = LocalTaskList.acquireTaskProvider(context.getContentResolver());
if (provider != null)
try {
LocalTaskList[] taskLists = (LocalTaskList[])LocalTaskList.find(account, provider, LocalTaskList.Factory.INSTANCE, null, null);
for (LocalTaskList taskList : taskLists) {
String url = taskList.getSyncId();
App.log.fine("Migrating task list " + url);
collections.add(url);
homeSets.add(HttpUrl.parse(url).resolve("../"));
}
} catch (CalendarStorageException e) {
App.log.log(Level.SEVERE, "Couldn't migrate task lists", e);
} finally {
provider.close();
}
if (!collections.isEmpty()) {
// insert CalDAV service
ContentValues values = new ContentValues();
values.put(Services.ACCOUNT_NAME, account.name);
values.put(Services.SERVICE, Services.SERVICE_CALDAV);
serviceCalDAV = db.insert(Services._TABLE, null, values);
// insert collections
for (String url : collections) {
values.clear();
values.put(Collections.SERVICE_ID, serviceCalDAV);
values.put(Collections.URL, url);
values.put(Collections.SYNC, 1);
db.insert(Collections._TABLE, null, values);
}
// insert home sets
for (HttpUrl homeSet : homeSets) {
values.clear();
values.put(HomeSets.SERVICE_ID, serviceCalDAV);
values.put(HomeSets.URL, homeSet.toString());
db.insert(HomeSets._TABLE, null, values);
}
}
} finally {
dbHelper.close();
}
// initiate service detection (refresh) to get display names, colors etc.
Intent refresh = new Intent(context, DavService.class);
refresh.setAction(DavService.ACTION_REFRESH_COLLECTIONS);
if (serviceCardDAV != null) {
refresh.putExtra(DavService.EXTRA_DAV_SERVICE_ID, serviceCardDAV);
context.startService(refresh);
}
if (serviceCalDAV != null) {
refresh.putExtra(DavService.EXTRA_DAV_SERVICE_ID, serviceCalDAV);
context.startService(refresh);
}
}
@SuppressWarnings({ "Recycle", "unused" })
private void update_3_4() {
setGroupMethod(GroupMethod.CATEGORIES);
}
public static class AppUpdatedReceiver extends BroadcastReceiver {
@Override
@SuppressLint("UnsafeProtectedBroadcastReceiver")
public void onReceive(Context context, Intent intent) {
App.log.info("DAVdroid was updated, checking for AccountSettings version");
// peek into AccountSettings to initiate a possible migration
AccountManager accountManager = AccountManager.get(context);
for (Account account : accountManager.getAccountsByType(Constants.ACCOUNT_TYPE))
try {
App.log.info("Checking account " + account.name);
new AccountSettings(context, account);
} catch (InvalidAccountException e) {
App.log.log(Level.SEVERE, "Couldn't check for updated account settings", e);
}
}
}
}

View File

@@ -0,0 +1,540 @@
/*
* 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.accounts.Account
import android.accounts.AccountManager
import android.annotation.SuppressLint
import android.content.*
import android.os.Build
import android.os.Bundle
import android.os.Parcel
import android.os.RemoteException
import android.provider.CalendarContract
import android.provider.ContactsContract
import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.model.CollectionInfo
import at.bitfire.davdroid.model.Credentials
import at.bitfire.davdroid.model.ServiceDB
import at.bitfire.davdroid.model.ServiceDB.*
import at.bitfire.davdroid.model.ServiceDB.Collections
import at.bitfire.davdroid.model.SyncState
import at.bitfire.davdroid.resource.LocalAddressBook
import at.bitfire.davdroid.resource.LocalCalendar
import at.bitfire.davdroid.resource.LocalTaskList
import at.bitfire.davdroid.settings.ISettings
import at.bitfire.ical4android.AndroidCalendar
import at.bitfire.ical4android.AndroidTaskList
import at.bitfire.ical4android.CalendarStorageException
import at.bitfire.ical4android.TaskProvider
import at.bitfire.vcard4android.ContactsStorageException
import at.bitfire.vcard4android.GroupMethod
import okhttp3.HttpUrl
import org.apache.commons.lang3.StringUtils
import org.dmfs.tasks.contract.TaskContract
import java.util.*
import java.util.logging.Level
/**
* Manages settings of an account.
*
* @throws InvalidAccountException on construction when the account doesn't exist (anymore)
*/
class AccountSettings(
val context: Context,
val settings: ISettings,
val account: Account
) {
companion object {
const val CURRENT_VERSION = 8
const val KEY_SETTINGS_VERSION = "version"
const val KEY_USERNAME = "user_name"
const val KEY_CERTIFICATE_ALIAS = "certificate_alias"
const val KEY_WIFI_ONLY = "wifi_only" // sync on WiFi only (default: false)
const val KEY_WIFI_ONLY_SSIDS = "wifi_only_ssids" // restrict sync to specific WiFi SSIDs
/** Time range limitation to the past [in days]
value = null default value (DEFAULT_TIME_RANGE_PAST_DAYS)
< 0 (-1) no limit
>= 0 entries more than n days in the past won't be synchronized
*/
const val KEY_TIME_RANGE_PAST_DAYS = "time_range_past_days"
const val DEFAULT_TIME_RANGE_PAST_DAYS = 90
/* Whether DAVdroid sets the local calendar color to the value from service DB at every sync
value = null (not existing) true (default)
"0" false */
const val KEY_MANAGE_CALENDAR_COLORS = "manage_calendar_colors"
/* Whether DAVdroid populates and uses CalendarContract.Colors
value = null (not existing) false (default)
"1" true */
const val KEY_EVENT_COLORS = "event_colors"
/** Contact group method:
value = null (not existing) groups as separate VCards (default)
"CATEGORIES" groups are per-contact CATEGORIES
*/
const val KEY_CONTACT_GROUP_METHOD = "contact_group_method"
const val SYNC_INTERVAL_MANUALLY = -1L
fun initialUserData(credentials: Credentials): Bundle {
val bundle = Bundle(2)
bundle.putString(KEY_SETTINGS_VERSION, CURRENT_VERSION.toString())
when (credentials.type) {
Credentials.Type.UsernamePassword ->
bundle.putString(KEY_USERNAME, credentials.userName)
Credentials.Type.ClientCertificate ->
bundle.putString(KEY_CERTIFICATE_ALIAS, credentials.certificateAlias)
}
return bundle
}
}
val accountManager: AccountManager = AccountManager.get(context)
init {
synchronized(AccountSettings::class.java) {
val versionStr = accountManager.getUserData(account, KEY_SETTINGS_VERSION) ?: throw InvalidAccountException(account)
var version = 0
try {
version = Integer.parseInt(versionStr)
} catch (e: NumberFormatException) {
}
Logger.log.fine("Account ${account.name} has version $version, current version: $CURRENT_VERSION")
if (version < CURRENT_VERSION)
update(version)
}
}
// authentication settings
fun credentials() = Credentials(
accountManager.getUserData(account, KEY_USERNAME),
accountManager.getPassword(account),
accountManager.getUserData(account, KEY_CERTIFICATE_ALIAS)
)
fun credentials(credentials: Credentials) {
accountManager.setUserData(account, KEY_USERNAME, credentials.userName)
accountManager.setPassword(account, credentials.password)
accountManager.setUserData(account, KEY_CERTIFICATE_ALIAS, credentials.certificateAlias)
}
// sync. settings
fun getSyncInterval(authority: String): Long? {
if (ContentResolver.getIsSyncable(account, authority) <= 0)
return null
return if (ContentResolver.getSyncAutomatically(account, authority))
ContentResolver.getPeriodicSyncs(account, authority).firstOrNull()?.period ?: SYNC_INTERVAL_MANUALLY
else
SYNC_INTERVAL_MANUALLY
}
fun setSyncInterval(authority: String, seconds: Long) {
if (seconds == SYNC_INTERVAL_MANUALLY) {
ContentResolver.setSyncAutomatically(account, authority, false)
} else {
ContentResolver.setSyncAutomatically(account, authority, true)
ContentResolver.addPeriodicSync(account, authority, Bundle(), seconds)
}
}
fun getSyncWifiOnly() = if (settings.has(KEY_WIFI_ONLY))
settings.getBoolean(KEY_WIFI_ONLY, false)
else
accountManager.getUserData(account, KEY_WIFI_ONLY) != null
fun setSyncWiFiOnly(wiFiOnly: Boolean) =
accountManager.setUserData(account, KEY_WIFI_ONLY, if (wiFiOnly) "1" else null)
fun getSyncWifiOnlySSIDs(): List<String>? = (if (settings.has(KEY_WIFI_ONLY_SSIDS))
settings.getString(KEY_WIFI_ONLY_SSIDS, null)
else
accountManager.getUserData(account, KEY_WIFI_ONLY_SSIDS))?.split(',')
fun setSyncWifiOnlySSIDs(ssids: List<String>?) =
accountManager.setUserData(account, KEY_WIFI_ONLY_SSIDS, StringUtils.trimToNull(ssids?.joinToString(",")))
// CalDAV settings
fun getTimeRangePastDays(): Int? {
val strDays = accountManager.getUserData(account, KEY_TIME_RANGE_PAST_DAYS)
return if (strDays != null) {
val days = Integer.valueOf(strDays)
if (days < 0) null else days
} else
DEFAULT_TIME_RANGE_PAST_DAYS
}
fun setTimeRangePastDays(days: Int?) =
accountManager.setUserData(account, KEY_TIME_RANGE_PAST_DAYS, (days ?: -1).toString())
fun getManageCalendarColors() = if (settings.has(KEY_MANAGE_CALENDAR_COLORS))
settings.getBoolean(KEY_MANAGE_CALENDAR_COLORS, false)
else
accountManager.getUserData(account, KEY_MANAGE_CALENDAR_COLORS) == null
fun setManageCalendarColors(manage: Boolean) =
accountManager.setUserData(account, KEY_MANAGE_CALENDAR_COLORS, if (manage) null else "0")
fun getEventColors() = if (settings.has(KEY_EVENT_COLORS))
settings.getBoolean(KEY_EVENT_COLORS, false)
else
accountManager.getUserData(account, KEY_EVENT_COLORS) != null
fun setEventColors(useColors: Boolean) =
accountManager.setUserData(account, KEY_EVENT_COLORS, if (useColors) "1" else null)
// CardDAV settings
fun getGroupMethod(): GroupMethod {
val name = settings.getString(KEY_CONTACT_GROUP_METHOD, null) ?:
accountManager.getUserData(account, KEY_CONTACT_GROUP_METHOD)
if (name != null)
try {
return GroupMethod.valueOf(name)
}
catch (e: IllegalArgumentException) {
}
return GroupMethod.GROUP_VCARDS
}
fun setGroupMethod(method: GroupMethod) {
accountManager.setUserData(account, KEY_CONTACT_GROUP_METHOD, method.name)
}
// update from previous account settings
private fun update(baseVersion: Int) {
for (toVersion in baseVersion+1 .. CURRENT_VERSION) {
val fromVersion = toVersion-1
Logger.log.info("Updating account ${account.name} from version $fromVersion to $toVersion")
try {
val updateProc = this::class.java.getDeclaredMethod("update_${fromVersion}_$toVersion")
updateProc.invoke(this)
Logger.log.info("Account version update successful")
accountManager.setUserData(account, KEY_SETTINGS_VERSION, toVersion.toString())
} catch (e: Exception) {
Logger.log.log(Level.SEVERE, "Couldn't update account settings", e)
}
}
}
@Suppress("unused")
/**
* There is a mistake in this method. [TaskContract.Tasks.SYNC_VERSION] is used to store the
* SEQUENCE and should not be used for the eTag.
*/
private fun update_7_8() {
TaskProvider.acquire(context, TaskProvider.ProviderName.OpenTasks)?.let { provider ->
// ETag is now in sync_version instead of sync1
// UID is now in _uid instead of sync2
provider.client.query(TaskProvider.syncAdapterUri(provider.tasksUri(), account),
arrayOf(TaskContract.Tasks._ID, TaskContract.Tasks.SYNC1, TaskContract.Tasks.SYNC2),
"${TaskContract.Tasks.ACCOUNT_TYPE}=? AND ${TaskContract.Tasks.ACCOUNT_NAME}=?",
arrayOf(account.type, account.name), null).use { cursor ->
while (cursor.moveToNext()) {
val id = cursor.getLong(0)
val eTag = cursor.getString(1)
val uid = cursor.getString(2)
val values = ContentValues(4)
values.put(TaskContract.Tasks._UID, uid)
values.put(TaskContract.Tasks.SYNC_VERSION, eTag)
values.putNull(TaskContract.Tasks.SYNC1)
values.putNull(TaskContract.Tasks.SYNC2)
Logger.log.log(Level.FINER, "Updating task $id", values)
provider.client.update(
TaskProvider.syncAdapterUri(ContentUris.withAppendedId(provider.tasksUri(), id), account),
values, null, null)
}
}
}
}
@Suppress("unused")
private fun update_6_7() {
// add calendar colors
context.contentResolver.acquireContentProviderClient(CalendarContract.AUTHORITY)?.let { provider ->
try {
AndroidCalendar.insertColors(provider, account)
} finally {
if (Build.VERSION.SDK_INT >= 24)
provider.close()
else
provider.release()
}
}
// update allowed WiFi settings key
val onlySSID = accountManager.getUserData(account, "wifi_only_ssid")
accountManager.setUserData(account, KEY_WIFI_ONLY_SSIDS, onlySSID)
accountManager.setUserData(account, "wifi_only_ssid", null)
}
@Suppress("unused")
@SuppressLint("ParcelClassLoader")
private fun update_5_6() {
context.contentResolver.acquireContentProviderClient(ContactsContract.AUTHORITY)?.let { provider ->
val parcel = Parcel.obtain()
try {
// don't run syncs during the migration
ContentResolver.setIsSyncable(account, ContactsContract.AUTHORITY, 0)
ContentResolver.setIsSyncable(account, context.getString(R.string.address_books_authority), 0)
ContentResolver.cancelSync(account, null)
// get previous address book settings (including URL)
val raw = ContactsContract.SyncState.get(provider, account)
if (raw == null)
Logger.log.info("No contacts sync state, ignoring account")
else {
parcel.unmarshall(raw, 0, raw.size)
parcel.setDataPosition(0)
val params = parcel.readBundle()
val url = params.getString("url")?.let { HttpUrl.parse(it) }
if (url == null)
Logger.log.info("No address book URL, ignoring account")
else {
// create new address book
val info = CollectionInfo(url)
info.type = CollectionInfo.Type.ADDRESS_BOOK
info.displayName = account.name
Logger.log.log(Level.INFO, "Creating new address book account", url)
val addressBookAccount = Account(LocalAddressBook.accountName(account, info), context.getString(R.string.account_type_address_book))
if (!accountManager.addAccountExplicitly(addressBookAccount, null, LocalAddressBook.initialUserData(account, info.url.toString())))
throw ContactsStorageException("Couldn't create address book account")
// move contacts to new address book
Logger.log.info("Moving contacts from $account to $addressBookAccount")
val newAccount = ContentValues(2)
newAccount.put(ContactsContract.RawContacts.ACCOUNT_NAME, addressBookAccount.name)
newAccount.put(ContactsContract.RawContacts.ACCOUNT_TYPE, addressBookAccount.type)
val affected = provider.update(ContactsContract.RawContacts.CONTENT_URI.buildUpon()
.appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_NAME, account.name)
.appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_TYPE, account.type)
.appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true").build(),
newAccount,
"${ContactsContract.RawContacts.ACCOUNT_NAME}=? AND ${ContactsContract.RawContacts.ACCOUNT_TYPE}=?",
arrayOf(account.name, account.type))
Logger.log.info("$affected contacts moved to new address book")
}
ContactsContract.SyncState.set(provider, account, null)
}
} catch(e: RemoteException) {
throw ContactsStorageException("Couldn't migrate contacts to new address book", e)
} finally {
parcel.recycle()
if (Build.VERSION.SDK_INT >= 24)
provider.close()
else
provider.release()
}
}
// update version number so that further syncs don't repeat the migration
accountManager.setUserData(account, KEY_SETTINGS_VERSION, "6")
// request sync of new address book account
ContentResolver.setIsSyncable(account, context.getString(R.string.address_books_authority), 1)
setSyncInterval(context.getString(R.string.address_books_authority), Constants.DEFAULT_SYNC_INTERVAL)
}
/* Android 7.1.1 OpenTasks fix */
@Suppress("unused")
private fun update_4_5() {
// call PackageChangedReceiver which then enables/disables OpenTasks sync when it's (not) available
PackageChangedReceiver.updateTaskSync(context)
}
@Suppress("unused")
private fun update_3_4() {
setGroupMethod(GroupMethod.CATEGORIES)
}
@Suppress("unused")
private fun update_2_3() {
// Don't show a warning for Android updates anymore
accountManager.setUserData(account, "last_android_version", null)
var serviceCardDAV: Long? = null
var serviceCalDAV: Long? = null
ServiceDB.OpenHelper(context).use { dbHelper ->
val db = dbHelper.writableDatabase
// we have to create the WebDAV Service database only from the old address book, calendar and task list URLs
// CardDAV: migrate address books
context.contentResolver.acquireContentProviderClient(ContactsContract.AUTHORITY)?.let { client ->
try {
val addrBook = LocalAddressBook(context, account, client)
val url = addrBook.url
Logger.log.fine("Migrating address book $url")
// insert CardDAV service
val values = ContentValues(3)
values.put(Services.ACCOUNT_NAME, account.name)
values.put(Services.SERVICE, Services.SERVICE_CARDDAV)
serviceCardDAV = db.insert(Services._TABLE, null, values)
// insert address book
values.clear()
values.put(Collections.SERVICE_ID, serviceCardDAV)
values.put(Collections.URL, url)
values.put(Collections.SYNC, 1)
db.insert(Collections._TABLE, null, values)
// insert home set
HttpUrl.parse(url)?.let {
val homeSet = it.resolve("../")
values.clear()
values.put(HomeSets.SERVICE_ID, serviceCardDAV)
values.put(HomeSets.URL, homeSet.toString())
db.insert(HomeSets._TABLE, null, values)
}
} catch (e: ContactsStorageException) {
Logger.log.log(Level.SEVERE, "Couldn't migrate address book", e)
} finally {
if (Build.VERSION.SDK_INT >= 24)
client.close()
else
@Suppress("deprecation")
client.release()
}
}
// CalDAV: migrate calendars + task lists
val collections = HashSet<String>()
val homeSets = HashSet<HttpUrl>()
context.contentResolver.acquireContentProviderClient(CalendarContract.AUTHORITY)?.let { client ->
try {
val calendars = AndroidCalendar.find(account, client, LocalCalendar.Factory, null, null)
for (calendar in calendars)
calendar.name?.let { url ->
Logger.log.fine("Migrating calendar $url")
collections.add(url)
HttpUrl.parse(url)?.resolve("../")?.let { homeSets.add(it) }
}
} catch (e: CalendarStorageException) {
Logger.log.log(Level.SEVERE, "Couldn't migrate calendars", e)
} finally {
if (Build.VERSION.SDK_INT >= 24)
client.close()
else
@Suppress("deprecation")
client.release()
}
}
AndroidTaskList.acquireTaskProvider(context)?.use { provider ->
try {
val taskLists = AndroidTaskList.find(account, provider, LocalTaskList.Factory, null, null)
for (taskList in taskLists)
taskList.syncId?.let { url ->
Logger.log.fine("Migrating task list $url")
collections.add(url)
HttpUrl.parse(url)?.resolve("../")?.let { homeSets.add(it) }
}
} catch (e: CalendarStorageException) {
Logger.log.log(Level.SEVERE, "Couldn't migrate task lists", e)
}
}
if (!collections.isEmpty()) {
// insert CalDAV service
val values = ContentValues(3)
values.put(Services.ACCOUNT_NAME, account.name)
values.put(Services.SERVICE, Services.SERVICE_CALDAV)
serviceCalDAV = db.insert(Services._TABLE, null, values)
// insert collections
for (url in collections) {
values.clear()
values.put(Collections.SERVICE_ID, serviceCalDAV)
values.put(Collections.URL, url)
values.put(Collections.SYNC, 1)
db.insert(Collections._TABLE, null, values)
}
// insert home sets
for (homeSet in homeSets) {
values.clear()
values.put(HomeSets.SERVICE_ID, serviceCalDAV)
values.put(HomeSets.URL, homeSet.toString())
db.insert(HomeSets._TABLE, null, values)
}
}
}
// initiate service detection (refresh) to get display names, colors etc.
val refresh = Intent(context, DavService::class.java)
refresh.action = DavService.ACTION_REFRESH_COLLECTIONS
serviceCardDAV?.let {
refresh.putExtra(DavService.EXTRA_DAV_SERVICE_ID, it)
context.startService(refresh)
}
serviceCalDAV?.let {
refresh.putExtra(DavService.EXTRA_DAV_SERVICE_ID, it)
context.startService(refresh)
}
}
@Suppress("unused")
@SuppressLint("Recycle")
private fun update_1_2() {
/* - KEY_ADDRESSBOOK_URL ("addressbook_url"),
- KEY_ADDRESSBOOK_CTAG ("addressbook_ctag"),
- KEY_ADDRESSBOOK_VCARD_VERSION ("addressbook_vcard_version") are not used anymore (now stored in ContactsContract.SyncState)
- KEY_LAST_ANDROID_VERSION ("last_android_version") has been added
*/
// move previous address book info to ContactsContract.SyncState
val provider = context.contentResolver.acquireContentProviderClient(ContactsContract.AUTHORITY) ?:
throw ContactsStorageException("Couldn't access Contacts provider")
try {
val addr = LocalAddressBook(context, account, provider)
// until now, ContactsContract.Settings.UNGROUPED_VISIBLE was not set explicitly
val values = ContentValues()
values.put(ContactsContract.Settings.UNGROUPED_VISIBLE, 1)
addr.settings = values
val url = accountManager.getUserData(account, "addressbook_url")
if (!url.isNullOrEmpty())
addr.url = url
accountManager.setUserData(account, "addressbook_url", null)
val cTag = accountManager.getUserData (account, "addressbook_ctag")
if (!cTag.isNullOrEmpty())
addr.lastSyncState = SyncState(SyncState.Type.CTAG, cTag)
accountManager.setUserData(account, "addressbook_ctag", null)
} finally {
if (Build.VERSION.SDK_INT >= 24)
provider.close()
else
@Suppress("deprecation")
provider.release()
}
}
}

View File

@@ -1,43 +0,0 @@
/*
* Copyright © 2013 2016 Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
*/
package at.bitfire.davdroid;
import android.accounts.OnAccountsUpdateListener;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import java.util.LinkedList;
import java.util.List;
public class AccountsChangedReceiver extends BroadcastReceiver {
protected static final List<OnAccountsUpdateListener> listeners = new LinkedList<>();
@Override
public void onReceive(Context context, Intent intent) {
Intent serviceIntent = new Intent(context, DavService.class);
serviceIntent.setAction(DavService.ACTION_ACCOUNTS_UPDATED);
context.startService(serviceIntent);
for (OnAccountsUpdateListener listener : listeners)
listener.onAccountsUpdated(null);
}
public static void registerListener(OnAccountsUpdateListener listener, boolean callImmediately) {
listeners.add(listener);
if (callImmediately)
listener.onAccountsUpdated(null);
}
public static void unregisterListener(OnAccountsUpdateListener listener) {
listeners.remove(listener);
}
}

View File

@@ -1,145 +0,0 @@
/*
* Copyright © 2013 2016 Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
*/
package at.bitfire.davdroid;
import android.app.Application;
import android.app.NotificationManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.BitmapDrawable;
import android.support.v7.app.NotificationCompat;
import android.util.Log;
import org.apache.commons.lang3.time.DateFormatUtils;
import java.io.File;
import java.io.IOException;
import java.util.logging.FileHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.net.ssl.HostnameVerifier;
import at.bitfire.davdroid.log.LogcatHandler;
import at.bitfire.davdroid.log.PlainTextFormatter;
import at.bitfire.davdroid.model.ServiceDB;
import at.bitfire.davdroid.model.Settings;
import de.duenndns.ssl.MemorizingTrustManager;
import lombok.Cleanup;
import lombok.Getter;
import okhttp3.internal.tls.OkHostnameVerifier;
public class App extends Application {
public static final String FLAVOR_GOOGLE_PLAY = "gplay";
public static final String LOG_TO_EXTERNAL_STORAGE = "logToExternalStorage";
@Getter
private static MemorizingTrustManager memorizingTrustManager;
@Getter
private static SSLSocketFactoryCompat sslSocketFactoryCompat;
@Getter
private static HostnameVerifier hostnameVerifier;
public final static Logger log = Logger.getLogger("davdroid");
static {
at.bitfire.dav4android.Constants.log = Logger.getLogger("davdroid.dav4android");
}
@Override
public void onCreate() {
super.onCreate();
// initialize MemorizingTrustManager
memorizingTrustManager = new MemorizingTrustManager(this);
sslSocketFactoryCompat = new SSLSocketFactoryCompat(memorizingTrustManager);
hostnameVerifier = memorizingTrustManager.wrapHostnameVerifier(OkHostnameVerifier.INSTANCE);
// initializer logger
reinitLogger();
}
public void reinitLogger() {
// don't use Android default logging, we have our own handlers
log.setUseParentHandlers(false);
@Cleanup ServiceDB.OpenHelper dbHelper = new ServiceDB.OpenHelper(this);
Settings settings = new Settings(dbHelper.getReadableDatabase());
boolean logToFile = settings.getBoolean(LOG_TO_EXTERNAL_STORAGE, false),
logVerbose = logToFile || Log.isLoggable(log.getName(), Log.DEBUG);
// set logging level according to preferences
log.setLevel(logVerbose ? Level.ALL : Level.INFO);
// remove all handlers
for (Handler handler : log.getHandlers())
log.removeHandler(handler);
// add logcat handler
log.addHandler(LogcatHandler.INSTANCE);
NotificationManager nm = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
// log to external file according to preferences
if (logToFile) {
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
builder .setSmallIcon(R.drawable.ic_sd_storage_light)
.setLargeIcon(((BitmapDrawable)getResources().getDrawable(R.drawable.ic_launcher)).getBitmap())
.setContentTitle(getString(R.string.logging_davdroid_file_logging))
.setLocalOnly(true);
File dir = getExternalFilesDir(null);
if (dir != null)
try {
String fileName = new File(dir, "davdroid-" + android.os.Process.myPid() + "-" +
DateFormatUtils.format(System.currentTimeMillis(), "yyyyMMdd-HHmmss") + ".txt").toString();
log.info("Logging to " + fileName);
FileHandler fileHandler = new FileHandler(fileName);
fileHandler.setFormatter(PlainTextFormatter.DEFAULT);
log.addHandler(fileHandler);
builder .setContentText(dir.getPath())
.setSubText(getString(R.string.logging_to_external_storage_warning))
.setCategory(NotificationCompat.CATEGORY_STATUS)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setStyle(new NotificationCompat.BigTextStyle()
.bigText(getString(R.string.logging_to_external_storage, dir.getPath())))
.setOngoing(true);
} catch (IOException e) {
log.log(Level.SEVERE, "Couldn't create external log file", e);
builder .setContentText(getString(R.string.logging_couldnt_create_file, e.getLocalizedMessage()))
.setCategory(NotificationCompat.CATEGORY_ERROR);
}
else
builder.setContentText(getString(R.string.logging_no_external_storage));
nm.notify(Constants.NOTIFICATION_EXTERNAL_FILE_LOGGING, builder.build());
} else
nm.cancel(Constants.NOTIFICATION_EXTERNAL_FILE_LOGGING);
}
public static class ReinitLoggingReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
log.info("Received broadcast: re-initializing logger");
App app = (App)context.getApplicationContext();
app.reinitLogger();
}
}
}

View File

@@ -0,0 +1,115 @@
/*
* 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.app.Application
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.graphics.Bitmap
import android.graphics.drawable.BitmapDrawable
import android.net.Uri
import android.os.Build
import android.os.StrictMode
import android.support.v7.app.AppCompatDelegate
import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.ui.NotificationUtils
import kotlin.concurrent.thread
class App: Application() {
companion object {
const val FLAVOR_GOOGLE_PLAY = "gplay"
const val FLAVOR_ICLOUD = "icloud"
const val FLAVOR_MANAGED = "managed"
const val FLAVOR_SOLDUPE = "soldupe"
const val FLAVOR_STANDARD = "standard"
const val ORGANIZATION = "organization"
const val ORGANIZATION_LOGO_URL = "logo_url"
const val SUPPORT_HOMEPAGE = "support_homepage_url"
const val SUPPORT_PHONE = "support_phone_number"
const val SUPPORT_EMAIL = "support_email_address"
const val MAX_ACCOUNTS = "max_accounts"
const val DISTRUST_SYSTEM_CERTIFICATES = "distrust_system_certs"
const val OVERRIDE_PROXY = "override_proxy"
const val OVERRIDE_PROXY_HOST = "override_proxy_host"
const val OVERRIDE_PROXY_PORT = "override_proxy_port"
const val OVERRIDE_PROXY_HOST_DEFAULT = "localhost"
const val OVERRIDE_PROXY_PORT_DEFAULT = 8118
fun getLauncherBitmap(context: Context): Bitmap? {
val drawableLogo = if (android.os.Build.VERSION.SDK_INT >= 21)
context.getDrawable(R.mipmap.ic_launcher)
else
@Suppress("deprecation")
context.resources.getDrawable(R.mipmap.ic_launcher)
return if (drawableLogo is BitmapDrawable)
drawableLogo.bitmap
else
null
}
fun homepageUrl(context: Context) =
Uri.parse(context.getString(R.string.homepage_url)).buildUpon()
.appendQueryParameter("pk_campaign", BuildConfig.APPLICATION_ID)
.appendQueryParameter("pk_kwd", context::class.java.simpleName)
.appendQueryParameter("app-version", BuildConfig.VERSION_NAME)
.build()!!
}
override fun onCreate() {
super.onCreate()
Logger.initialize(this)
if (BuildConfig.DEBUG) {
StrictMode.setVmPolicy(StrictMode.VmPolicy.Builder()
.detectActivityLeaks()
.detectFileUriExposure()
.detectLeakedClosableObjects()
.detectLeakedRegistrationObjects()
.detectLeakedSqlLiteObjects()
.penaltyLog()
.build())
// main thread
StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.Builder()
.detectAll()
.penaltyLog()
.build())
}
if (Build.VERSION.SDK_INT <= 21)
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
NotificationUtils.createChannels(this)
// don't block UI for some background checks
thread {
// watch installed/removed apps
val tasksFilter = IntentFilter()
tasksFilter.addAction(Intent.ACTION_PACKAGE_ADDED)
tasksFilter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED)
tasksFilter.addDataScheme("package")
registerReceiver(PackageChangedReceiver(), tasksFilter)
// check whether a tasks app is currently installed
PackageChangedReceiver.updateTaskSync(this)
}
}
}

View File

@@ -1,33 +0,0 @@
/*
* Copyright © 2013 2015 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 java.lang.reflect.Array;
public class ArrayUtils {
@SuppressWarnings("unchecked")
public static <T> T[][] partition(T[] bigArray, int max) {
int nItems = bigArray.length;
int nPartArrays = (nItems + max-1)/max;
T[][] partArrays = (T[][])Array.newInstance(bigArray.getClass().getComponentType(), nPartArrays, 0);
// nItems is now the number of remaining items
for (int i = 0; nItems > 0; i++) {
int n = (nItems < max) ? nItems : max;
partArrays[i] = (T[])Array.newInstance(bigArray.getClass().getComponentType(), n);
System.arraycopy(bigArray, i*max, partArrays[i], 0, n);
nItems -= n;
}
return partArrays;
}
}

View File

@@ -1,29 +0,0 @@
/*
* Copyright © 2013 2015 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.net.Uri;
public class Constants {
public static final String
ACCOUNT_TYPE = "bitfire.at.davdroid";
// notification IDs
public final static int
NOTIFICATION_ACCOUNT_SETTINGS_UPDATED = 0,
NOTIFICATION_EXTERNAL_FILE_LOGGING = 1,
NOTIFICATION_REFRESH_COLLECTIONS = 2,
NOTIFICATION_CONTACTS_SYNC = 10,
NOTIFICATION_CALENDAR_SYNC = 11,
NOTIFICATION_TASK_SYNC = 12,
NOTIFICATION_PERMISSIONS = 20;
public static final Uri webUri = Uri.parse("https://davdroid.bitfire.at/?pk_campaign=davdroid-app");
}

View File

@@ -0,0 +1,30 @@
/*
* 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
object Constants {
const val DAVDROID_GREEN_RGBA = 0xFF8bc34a.toInt()
const val DEFAULT_SYNC_INTERVAL = 4 * 3600L // 4 hours
/**
* Context label for [org.apache.commons.lang3.exception.ContextedException].
* Context value is the [at.bitfire.davdroid.resource.LocalResource]
* which is related to the exception cause.
*/
const val EXCEPTION_CONTEXT_LOCAL_RESOURCE = "localResource"
/**
* Context label for [org.apache.commons.lang3.exception.ContextedException].
* Context value is the [okhttp3.HttpUrl] of the remote resource
* which is related to the exception cause.
*/
const val EXCEPTION_CONTEXT_REMOTE_RESOURCE = "remoteResource"
}

View File

@@ -0,0 +1,165 @@
/*
* 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.os.Build
import at.bitfire.davdroid.log.Logger
import java.io.IOException
import java.net.InetAddress
import java.net.Socket
import java.security.GeneralSecurityException
import java.util.*
import javax.net.ssl.*
/**
* Custom TLS socket factory with support for
* - enabling/disabling algorithms depending on the Android version,
* - client certificate authentication
*/
class CustomTlsSocketFactory(
keyManager: KeyManager?,
trustManager: X509TrustManager
): SSLSocketFactory() {
private var delegate: SSLSocketFactory
companion object {
// Android 5.0+ (API level 21) provides reasonable default settings
// but it still allows SSLv3
// https://developer.android.com/reference/javax/net/ssl/SSLSocket.html
var protocols: Array<String>? = null
var cipherSuites: Array<String>? = null
init {
if (Build.VERSION.SDK_INT >= 23) {
// Since Android 6.0 (API level 23),
// - TLSv1.1 and TLSv1.2 is enabled by default
// - SSLv3 is disabled by default
// - all modern ciphers are activated by default
protocols = null
cipherSuites = null
Logger.log.fine("Using device default TLS protocols/ciphers")
} else {
(SSLSocketFactory.getDefault().createSocket() as? SSLSocket)?.use { socket ->
try {
/* set reasonable protocol versions */
// - enable all supported protocols (enables TLSv1.1 and TLSv1.2 on Android <5.0)
// - remove all SSL versions (especially SSLv3) because they're insecure now
val _protocols = LinkedList<String>()
for (protocol in socket.supportedProtocols.filterNot { it.contains("SSL", true) })
_protocols += protocol
Logger.log.info("Enabling (only) these TLS protocols: ${_protocols.joinToString(", ")}")
protocols = _protocols.toTypedArray()
/* set up reasonable cipher suites */
val knownCiphers = arrayOf(
// TLS 1.2
"TLS_RSA_WITH_AES_256_GCM_SHA384",
"TLS_RSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
// maximum interoperability
"TLS_RSA_WITH_3DES_EDE_CBC_SHA",
"SSL_RSA_WITH_3DES_EDE_CBC_SHA",
"TLS_RSA_WITH_AES_128_CBC_SHA",
// additionally
"TLS_RSA_WITH_AES_256_CBC_SHA",
"TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA"
)
val availableCiphers = socket.supportedCipherSuites
Logger.log.info("Available cipher suites: ${availableCiphers.joinToString(", ")}")
/* For maximum security, preferredCiphers should *replace* enabled ciphers (thus
* disabling ciphers which are enabled by default, but have become unsecure), but for
* the security level of DAVdroid and maximum compatibility, disabling of insecure
* ciphers should be a server-side task */
// for the final set of enabled ciphers, take the ciphers enabled by default, ...
val _cipherSuites = LinkedList<String>()
_cipherSuites.addAll(socket.enabledCipherSuites)
Logger.log.fine("Cipher suites enabled by default: ${_cipherSuites.joinToString(", ")}")
// ... add explicitly allowed ciphers ...
_cipherSuites.addAll(knownCiphers)
// ... and keep only those which are actually available
_cipherSuites.retainAll(availableCiphers)
Logger.log.info("Enabling (only) these TLS ciphers: " + _cipherSuites.joinToString(", "))
cipherSuites = _cipherSuites.toTypedArray()
} catch (e: IOException) {
Logger.log.severe("Couldn't determine default TLS settings")
}
}
}
}
}
init {
try {
val sslContext = SSLContext.getInstance("TLS")
sslContext.init(
if (keyManager != null) arrayOf(keyManager) else null,
arrayOf(trustManager),
null)
delegate = sslContext.socketFactory
} catch (e: GeneralSecurityException) {
throw IllegalStateException() // system has no TLS
}
}
override fun getDefaultCipherSuites(): Array<String>? = cipherSuites ?: delegate.defaultCipherSuites
override fun getSupportedCipherSuites(): Array<String>? = cipherSuites ?: delegate.supportedCipherSuites
override fun createSocket(s: Socket, host: String, port: Int, autoClose: Boolean): Socket {
val ssl = delegate.createSocket(s, host, port, autoClose)
if (ssl is SSLSocket)
upgradeTLS(ssl)
return ssl
}
override fun createSocket(host: String, port: Int): Socket {
val ssl = delegate.createSocket(host, port)
if (ssl is SSLSocket)
upgradeTLS(ssl)
return ssl
}
override fun createSocket(host: String, port: Int, localHost: InetAddress, localPort: Int): Socket {
val ssl = delegate.createSocket(host, port, localHost, localPort)
if (ssl is SSLSocket)
upgradeTLS(ssl)
return ssl
}
override fun createSocket(host: InetAddress, port: Int): Socket {
val ssl = delegate.createSocket(host, port)
if (ssl is SSLSocket)
upgradeTLS(ssl)
return ssl
}
override fun createSocket(address: InetAddress, port: Int, localAddress: InetAddress, localPort: Int): Socket {
val ssl = delegate.createSocket(address, port, localAddress, localPort)
if (ssl is SSLSocket)
upgradeTLS(ssl)
return ssl
}
private fun upgradeTLS(ssl: SSLSocket) {
protocols?.let { ssl.enabledProtocols = it }
cipherSuites?.let { ssl.enabledCipherSuites = it }
}
}

View File

@@ -1,427 +0,0 @@
/*
* Copyright © 2013 2016 Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
*/
package at.bitfire.davdroid;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.ContentValues;
import android.content.Intent;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.drawable.BitmapDrawable;
import android.os.Binder;
import android.os.IBinder;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.app.NotificationCompat;
import android.text.TextUtils;
import org.apache.commons.collections4.iterators.IteratorChain;
import org.apache.commons.collections4.iterators.SingletonIterator;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import at.bitfire.dav4android.DavResource;
import at.bitfire.dav4android.UrlUtils;
import at.bitfire.dav4android.exception.DavException;
import at.bitfire.dav4android.exception.HttpException;
import at.bitfire.dav4android.property.AddressbookHomeSet;
import at.bitfire.dav4android.property.CalendarHomeSet;
import at.bitfire.dav4android.property.CalendarProxyReadFor;
import at.bitfire.dav4android.property.CalendarProxyWriteFor;
import at.bitfire.dav4android.property.GroupMembership;
import at.bitfire.davdroid.model.CollectionInfo;
import at.bitfire.davdroid.model.ServiceDB.Collections;
import at.bitfire.davdroid.model.ServiceDB.HomeSets;
import at.bitfire.davdroid.model.ServiceDB.OpenHelper;
import at.bitfire.davdroid.model.ServiceDB.Services;
import at.bitfire.davdroid.ui.DebugInfoActivity;
import lombok.Cleanup;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
public class DavService extends Service {
public static final String
ACTION_ACCOUNTS_UPDATED = "accountsUpdated",
ACTION_REFRESH_COLLECTIONS = "refreshCollections",
EXTRA_DAV_SERVICE_ID = "davServiceID";
private final IBinder binder = new InfoBinder();
private final Set<Long> runningRefresh = new HashSet<>();
private final List<WeakReference<RefreshingStatusListener>> refreshingStatusListeners = new LinkedList<>();
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null) {
String action = intent.getAction();
long id = intent.getLongExtra(EXTRA_DAV_SERVICE_ID, -1);
switch (action) {
case ACTION_ACCOUNTS_UPDATED:
cleanupAccounts();
break;
case ACTION_REFRESH_COLLECTIONS:
if (runningRefresh.add(id)) {
new Thread(new RefreshCollections(id)).start();
for (WeakReference<RefreshingStatusListener> ref : refreshingStatusListeners) {
RefreshingStatusListener listener = ref.get();
if (listener != null)
listener.onDavRefreshStatusChanged(id, true);
}
}
break;
}
}
return START_NOT_STICKY;
}
/* BOUND SERVICE PART
for communicating with the activities
*/
@Override
public IBinder onBind(Intent intent) {
return binder;
}
public interface RefreshingStatusListener {
void onDavRefreshStatusChanged(long id, boolean refreshing);
}
public class InfoBinder extends Binder {
public boolean isRefreshing(long id) {
return runningRefresh.contains(id);
}
public void addRefreshingStatusListener(@NonNull RefreshingStatusListener listener, boolean callImmediate) {
refreshingStatusListeners.add(new WeakReference<>(listener));
if (callImmediate)
for (long id : runningRefresh)
listener.onDavRefreshStatusChanged(id, true);
}
public void removeRefreshingStatusListener(@NonNull RefreshingStatusListener listener) {
for (Iterator<WeakReference<RefreshingStatusListener>> iterator = refreshingStatusListeners.iterator(); iterator.hasNext(); ) {
RefreshingStatusListener item = iterator.next().get();
if (listener.equals(item))
iterator.remove();
}
}
}
/* ACTION RUNNABLES
which actually do the work
*/
void cleanupAccounts() {
App.log.info("Cleaning up orphaned accounts");
final OpenHelper dbHelper = new OpenHelper(this);
try {
SQLiteDatabase db = dbHelper.getWritableDatabase();
List<String> sqlAccountNames = new LinkedList<>();
AccountManager am = AccountManager.get(this);
for (Account account : am.getAccountsByType(Constants.ACCOUNT_TYPE))
sqlAccountNames.add(DatabaseUtils.sqlEscapeString(account.name));
if (sqlAccountNames.isEmpty())
db.delete(Services._TABLE, null, null);
else
db.delete(Services._TABLE, Services.ACCOUNT_NAME + " NOT IN (" + TextUtils.join(",", sqlAccountNames) + ")", null);
} finally {
dbHelper.close();
}
}
private class RefreshCollections implements Runnable {
final long service;
final OpenHelper dbHelper;
SQLiteDatabase db;
RefreshCollections(long davServiceId) {
this.service = davServiceId;
dbHelper = new OpenHelper(DavService.this);
}
@Override
public void run() {
Account account = null;
try {
db = dbHelper.getWritableDatabase();
String serviceType = serviceType();
App.log.info("Refreshing " + serviceType + " collections of service #" + service);
// get account
account = account();
// create authenticating OkHttpClient (credentials taken from account settings)
OkHttpClient httpClient = HttpClient.create(DavService.this, account);
// refresh home sets: principal
Set<HttpUrl> homeSets = readHomeSets();
HttpUrl principal = readPrincipal();
if (principal != null) {
App.log.fine("Querying principal for home sets");
DavResource dav = new DavResource(httpClient, principal);
queryHomeSets(serviceType, dav, homeSets);
// refresh home sets: calendar-proxy-read/write-for
CalendarProxyReadFor proxyRead = (CalendarProxyReadFor)dav.properties.get(CalendarProxyReadFor.NAME);
if (proxyRead != null)
for (String href : proxyRead.principals) {
App.log.fine("Principal is a read-only proxy for " + href + ", checking for home sets");
queryHomeSets(serviceType, new DavResource(httpClient, dav.location.resolve(href)), homeSets);
}
CalendarProxyWriteFor proxyWrite = (CalendarProxyWriteFor)dav.properties.get(CalendarProxyWriteFor.NAME);
if (proxyWrite != null)
for (String href : proxyWrite.principals) {
App.log.fine("Principal is a read-write proxy for " + href + ", checking for home sets");
queryHomeSets(serviceType, new DavResource(httpClient, dav.location.resolve(href)), homeSets);
}
// refresh home sets: direct group memberships
GroupMembership groupMembership = (GroupMembership)dav.properties.get(GroupMembership.NAME);
if (groupMembership != null)
for (String href : groupMembership.hrefs) {
App.log.fine("Principal is member of group " + href + ", checking for home sets");
DavResource group = new DavResource(httpClient, dav.location.resolve(href));
try {
queryHomeSets(serviceType, group, homeSets);
} catch(HttpException|DavException e) {
App.log.log(Level.WARNING, "Couldn't query member group ", e);
}
}
}
// now refresh collections (taken from home sets)
Map<HttpUrl, CollectionInfo> collections = readCollections();
// (remember selections before)
Set<HttpUrl> selectedCollections = new HashSet<>();
for (CollectionInfo info : collections.values())
if (info.selected)
selectedCollections.add(HttpUrl.parse(info.url));
for (Iterator<HttpUrl> itHomeSets = homeSets.iterator(); itHomeSets.hasNext(); ) {
HttpUrl homeSet = itHomeSets.next();
App.log.fine("Listing home set " + homeSet);
DavResource dav = new DavResource(httpClient, homeSet);
try {
dav.propfind(1, CollectionInfo.DAV_PROPERTIES);
IteratorChain<DavResource> itCollections = new IteratorChain<>(dav.members.iterator(), new SingletonIterator(dav));
while (itCollections.hasNext()) {
DavResource member = itCollections.next();
CollectionInfo info = CollectionInfo.fromDavResource(member);
info.confirmed = true;
App.log.log(Level.FINE, "Found collection", info);
if ((serviceType.equals(Services.SERVICE_CARDDAV) && info.type == CollectionInfo.Type.ADDRESS_BOOK) ||
(serviceType.equals(Services.SERVICE_CALDAV) && info.type == CollectionInfo.Type.CALENDAR))
collections.put(member.location, info);
}
} catch(HttpException e) {
if (e.status == 403 || e.status == 404 || e.status == 410)
// delete home set only if it was not accessible (40x)
itHomeSets.remove();
}
}
// check/refresh unconfirmed collections
for (Iterator<Map.Entry<HttpUrl, CollectionInfo>> iterator = collections.entrySet().iterator(); iterator.hasNext(); ) {
Map.Entry<HttpUrl, CollectionInfo> entry = iterator.next();
HttpUrl url = entry.getKey();
CollectionInfo info = entry.getValue();
if (!info.confirmed)
try {
DavResource dav = new DavResource(httpClient, url);
dav.propfind(0, CollectionInfo.DAV_PROPERTIES);
info = CollectionInfo.fromDavResource(dav);
info.confirmed = true;
// remove unusable collections
if ((serviceType.equals(Services.SERVICE_CARDDAV) && info.type != CollectionInfo.Type.ADDRESS_BOOK) ||
(serviceType.equals(Services.SERVICE_CALDAV) && info.type != CollectionInfo.Type.CALENDAR))
iterator.remove();
} catch(HttpException e) {
if (e.status == 403 || e.status == 404 || e.status == 410)
// delete collection only if it was not accessible (40x)
iterator.remove();
else
throw e;
}
}
// restore selections
for (HttpUrl url : selectedCollections) {
CollectionInfo info = collections.get(url);
if (info != null)
info.selected = true;
}
try {
db.beginTransactionNonExclusive();
saveHomeSets(homeSets);
saveCollections(collections.values());
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
} catch(InvalidAccountException e) {
App.log.log(Level.SEVERE, "Invalid account", e);
} catch(IOException|HttpException|DavException e) {
App.log.log(Level.SEVERE, "Couldn't refresh collection list", e);
Intent debugIntent = new Intent(DavService.this, DebugInfoActivity.class);
debugIntent.putExtra(DebugInfoActivity.KEY_THROWABLE, e);
if (account != null)
debugIntent.putExtra(DebugInfoActivity.KEY_ACCOUNT, account);
NotificationManager nm = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
Notification notify = new NotificationCompat.Builder(DavService.this)
.setSmallIcon(R.drawable.ic_error_light)
.setLargeIcon(((BitmapDrawable)getResources().getDrawable(R.drawable.ic_launcher)).getBitmap())
.setContentTitle(getString(R.string.dav_service_refresh_failed))
.setContentText(getString(R.string.dav_service_refresh_couldnt_refresh))
.setContentIntent(PendingIntent.getActivity(DavService.this, 0, debugIntent, PendingIntent.FLAG_UPDATE_CURRENT))
.build();
nm.notify(Constants.NOTIFICATION_REFRESH_COLLECTIONS, notify);
} finally {
dbHelper.close();
runningRefresh.remove(service);
for (WeakReference<RefreshingStatusListener> ref : refreshingStatusListeners) {
RefreshingStatusListener listener = ref.get();
if (listener != null)
listener.onDavRefreshStatusChanged(service, false);
}
}
}
/**
* Checks if the given URL defines home sets and adds them to the home set list.
* @param serviceType CalDAV/CardDAV (calendar home set / addressbook home set)
* @param dav DavResource to check
* @param homeSets set where found home set URLs will be put into
*/
private void queryHomeSets(String serviceType, DavResource dav, Set<HttpUrl> homeSets) throws IOException, HttpException, DavException {
if (Services.SERVICE_CARDDAV.equals(serviceType)) {
dav.propfind(0, AddressbookHomeSet.NAME, GroupMembership.NAME);
AddressbookHomeSet addressbookHomeSet = (AddressbookHomeSet)dav.properties.get(AddressbookHomeSet.NAME);
if (addressbookHomeSet != null)
for (String href : addressbookHomeSet.hrefs)
homeSets.add(UrlUtils.withTrailingSlash(dav.location.resolve(href)));
} else if (Services.SERVICE_CALDAV.equals(serviceType)) {
dav.propfind(0, CalendarHomeSet.NAME, CalendarProxyReadFor.NAME, CalendarProxyWriteFor.NAME, GroupMembership.NAME);
CalendarHomeSet calendarHomeSet = (CalendarHomeSet)dav.properties.get(CalendarHomeSet.NAME);
if (calendarHomeSet != null)
for (String href : calendarHomeSet.hrefs)
homeSets.add(UrlUtils.withTrailingSlash(dav.location.resolve(href)));
}
}
@NonNull
private Account account() {
@Cleanup Cursor cursor = db.query(Services._TABLE, new String[] { Services.ACCOUNT_NAME }, Services.ID + "=?", new String[] { String.valueOf(service) }, null, null, null);
if (cursor.moveToNext()) {
return new Account(cursor.getString(0), Constants.ACCOUNT_TYPE);
} else
throw new IllegalArgumentException("Service not found");
}
@NonNull
private String serviceType() {
@Cleanup Cursor cursor = db.query(Services._TABLE, new String[] { Services.SERVICE }, Services.ID + "=?", new String[] { String.valueOf(service) }, null, null, null);
if (cursor.moveToNext())
return cursor.getString(0);
else
throw new IllegalArgumentException("Service not found");
}
@Nullable
private HttpUrl readPrincipal() {
@Cleanup Cursor cursor = db.query(Services._TABLE, new String[] { Services.PRINCIPAL }, Services.ID + "=?", new String[] { String.valueOf(service) }, null, null, null);
if (cursor.moveToNext()) {
String principal = cursor.getString(0);
if (principal != null)
return HttpUrl.parse(cursor.getString(0));
}
return null;
}
@NonNull
private Set<HttpUrl> readHomeSets() {
Set<HttpUrl> homeSets = new LinkedHashSet<>();
@Cleanup Cursor cursor = db.query(HomeSets._TABLE, new String[] { HomeSets.URL }, HomeSets.SERVICE_ID + "=?", new String[] { String.valueOf(service) }, null, null, null);
while (cursor.moveToNext())
homeSets.add(HttpUrl.parse(cursor.getString(0)));
return homeSets;
}
private void saveHomeSets(Set<HttpUrl> homeSets) {
db.delete(HomeSets._TABLE, HomeSets.SERVICE_ID + "=?", new String[] { String.valueOf(service) });
for (HttpUrl homeSet : homeSets) {
ContentValues values = new ContentValues(1);
values.put(HomeSets.SERVICE_ID, service);
values.put(HomeSets.URL, homeSet.toString());
db.insertOrThrow(HomeSets._TABLE, null, values);
}
}
@NonNull
private Map<HttpUrl, CollectionInfo> readCollections() {
Map<HttpUrl, CollectionInfo> collections = new LinkedHashMap<>();
@Cleanup Cursor cursor = db.query(Collections._TABLE, null, Collections.SERVICE_ID + "=?", new String[]{String.valueOf(service)}, null, null, null);
while (cursor.moveToNext()) {
ContentValues values = new ContentValues();
DatabaseUtils.cursorRowToContentValues(cursor, values);
collections.put(HttpUrl.parse(values.getAsString(Collections.URL)), CollectionInfo.fromDB(values));
}
return collections;
}
private void saveCollections(Iterable<CollectionInfo> collections) {
db.delete(Collections._TABLE, HomeSets.SERVICE_ID + "=?", new String[] { String.valueOf(service) });
for (CollectionInfo collection : collections) {
ContentValues values = collection.toDB();
App.log.log(Level.FINE, "Saving collection", values);
values.put(Collections.SERVICE_ID, service);
db.insertWithOnConflict(Collections._TABLE, null, values, SQLiteDatabase.CONFLICT_REPLACE);
}
}
}
}

View File

@@ -0,0 +1,405 @@
/*
* 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.accounts.Account
import android.app.PendingIntent
import android.app.Service
import android.content.ContentResolver
import android.content.ContentValues
import android.content.Intent
import android.database.DatabaseUtils
import android.database.sqlite.SQLiteDatabase
import android.os.Binder
import android.os.Bundle
import android.support.v4.app.NotificationCompat
import android.support.v4.app.NotificationManagerCompat
import at.bitfire.dav4android.DavResource
import at.bitfire.dav4android.Response
import at.bitfire.dav4android.UrlUtils
import at.bitfire.dav4android.exception.DavException
import at.bitfire.dav4android.exception.HttpException
import at.bitfire.dav4android.property.*
import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.model.CollectionInfo
import at.bitfire.davdroid.model.ServiceDB.*
import at.bitfire.davdroid.model.ServiceDB.Collections
import at.bitfire.davdroid.settings.Settings
import at.bitfire.davdroid.ui.DebugInfoActivity
import at.bitfire.davdroid.ui.NotificationUtils
import okhttp3.HttpUrl
import okhttp3.OkHttpClient
import java.io.IOException
import java.lang.ref.WeakReference
import java.util.*
import java.util.logging.Level
import kotlin.concurrent.thread
class DavService: Service() {
companion object {
const val ACTION_REFRESH_COLLECTIONS = "refreshCollections"
const val EXTRA_DAV_SERVICE_ID = "davServiceID"
/** Initialize a forced synchronization. Expects intent data
to be an URI of this format:
contents://<authority>/<account.type>/<account name>
**/
const val ACTION_FORCE_SYNC = "forceSync"
}
private val runningRefresh = HashSet<Long>()
private val refreshingStatusListeners = LinkedList<WeakReference<RefreshingStatusListener>>()
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
intent?.let {
val id = intent.getLongExtra(EXTRA_DAV_SERVICE_ID, -1)
when (intent.action) {
ACTION_REFRESH_COLLECTIONS ->
if (runningRefresh.add(id)) {
thread { refreshCollections(id) }
refreshingStatusListeners.forEach { it.get()?.onDavRefreshStatusChanged(id, true) }
}
ACTION_FORCE_SYNC -> {
val authority = intent.data.authority
val account = Account(
intent.data.pathSegments[1],
intent.data.pathSegments[0]
)
forceSync(authority, account)
}
}
}
return START_NOT_STICKY
}
/* BOUND SERVICE PART
for communicating with the activities
*/
interface RefreshingStatusListener {
fun onDavRefreshStatusChanged(id: Long, refreshing: Boolean)
}
private val binder = InfoBinder()
inner class InfoBinder: Binder() {
fun isRefreshing(id: Long) = runningRefresh.contains(id)
fun addRefreshingStatusListener(listener: RefreshingStatusListener, callImmediate: Boolean) {
refreshingStatusListeners += WeakReference<RefreshingStatusListener>(listener)
if (callImmediate)
runningRefresh.forEach { id -> listener.onDavRefreshStatusChanged(id, true) }
}
fun removeRefreshingStatusListener(listener: RefreshingStatusListener) {
val iter = refreshingStatusListeners.iterator()
while (iter.hasNext()) {
val item = iter.next().get()
if (listener == item)
iter.remove()
}
}
}
override fun onBind(intent: Intent?) = binder
/* ACTION RUNNABLES
which actually do the work
*/
private fun forceSync(authority: String, account: Account) {
Logger.log.info("Forcing $authority synchronization of $account")
val extras = Bundle(2)
extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true) // manual sync
extras.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true) // run immediately (don't queue)
ContentResolver.requestSync(account, authority, extras)
}
private fun refreshCollections(service: Long) {
OpenHelper(this@DavService).use { dbHelper ->
val db = dbHelper.writableDatabase
val serviceType by lazy {
db.query(Services._TABLE, arrayOf(Services.SERVICE), "${Services.ID}=?", arrayOf(service.toString()), null, null, null)?.use { cursor ->
if (cursor.moveToNext())
return@lazy cursor.getString(0)
} ?: throw IllegalArgumentException("Service not found")
}
val account by lazy {
db.query(Services._TABLE, arrayOf(Services.ACCOUNT_NAME), "${Services.ID}=?", arrayOf(service.toString()), null, null, null)?.use { cursor ->
if (cursor.moveToNext())
return@lazy Account(cursor.getString(0), getString(R.string.account_type))
}
throw IllegalArgumentException("Account not found")
}
val homeSets by lazy {
val homeSets = mutableSetOf<HttpUrl>()
db.query(HomeSets._TABLE, arrayOf(HomeSets.URL), "${HomeSets.SERVICE_ID}=?", arrayOf(service.toString()), null, null, null)?.use { cursor ->
while (cursor.moveToNext())
HttpUrl.parse(cursor.getString(0))?.let { homeSets += it }
}
homeSets
}
val collections by lazy {
val collections = mutableMapOf<HttpUrl, CollectionInfo>()
db.query(Collections._TABLE, null, "${Collections.SERVICE_ID}=?", arrayOf(service.toString()), null, null, null)?.use { cursor ->
while (cursor.moveToNext()) {
val values = ContentValues(cursor.columnCount)
DatabaseUtils.cursorRowToContentValues(cursor, values)
values.getAsString(Collections.URL)?.let { url ->
HttpUrl.parse(url)?.let { collections.put(it, CollectionInfo(values)) }
}
}
}
collections
}
fun readPrincipal(): HttpUrl? {
db.query(Services._TABLE, arrayOf(Services.PRINCIPAL), "${Services.ID}=?", arrayOf(service.toString()), null, null, null)?.use { cursor ->
if (cursor.moveToNext())
cursor.getString(0)?.let { return HttpUrl.parse(it) }
}
return null
}
/**
* Checks if the given URL defines home sets and adds them to the home set list.
*
* @throws IOException
* @throws HttpException
* @throws DavException
*/
fun queryHomeSets(client: OkHttpClient, url: HttpUrl, recurse: Boolean = true) {
var related = setOf<HttpUrl>()
fun findRelated(root: HttpUrl, dav: Response) {
// refresh home sets: calendar-proxy-read/write-for
dav[CalendarProxyReadFor::class.java]?.let {
for (href in it.hrefs) {
Logger.log.fine("Principal is a read-only proxy for $href, checking for home sets")
root.resolve(href)?.let {
related += it
}
}
}
dav[CalendarProxyWriteFor::class.java]?.let {
for (href in it.hrefs) {
Logger.log.fine("Principal is a read/write proxy for $href, checking for home sets")
root.resolve(href)?.let {
related += it
}
}
}
// refresh home sets: direct group memberships
dav[GroupMembership::class.java]?.let {
for (href in it.hrefs) {
Logger.log.fine("Principal is member of group $href, checking for home sets")
root.resolve(href)?.let {
related += it
}
}
}
}
val dav = DavResource(client, url)
when (serviceType) {
Services.SERVICE_CARDDAV ->
try {
dav.propfind(0, AddressbookHomeSet.NAME, GroupMembership.NAME) { response, _ ->
response[AddressbookHomeSet::class.java]?.let { homeSet ->
for (href in homeSet.hrefs)
dav.location.resolve(href)?.let { homeSets += UrlUtils.withTrailingSlash(it) }
}
if (recurse)
findRelated(dav.location, response)
}
} catch (e: HttpException) {
if (e.code/100 == 4)
Logger.log.log(Level.INFO, "Ignoring Client Error 4xx while looking for addressbook home sets", e)
else
throw e
}
Services.SERVICE_CALDAV -> {
try {
dav.propfind(0, CalendarHomeSet.NAME, CalendarProxyReadFor.NAME, CalendarProxyWriteFor.NAME, GroupMembership.NAME) { response, _ ->
response[CalendarHomeSet::class.java]?.let { homeSet ->
for (href in homeSet.hrefs)
dav.location.resolve(href)?.let { homeSets.add(UrlUtils.withTrailingSlash(it)) }
}
if (recurse)
findRelated(dav.location, response)
}
} catch (e: HttpException) {
if (e.code/100 == 4)
Logger.log.log(Level.INFO, "Ignoring Client Error 4xx while looking for calendar home sets", e)
else
throw e
}
}
}
for (resource in related)
queryHomeSets(client, resource, false)
}
fun saveHomeSets() {
db.delete(HomeSets._TABLE, "${HomeSets.SERVICE_ID}=?", arrayOf(service.toString()))
for (homeSet in homeSets) {
val values = ContentValues(2)
values.put(HomeSets.SERVICE_ID, service)
values.put(HomeSets.URL, homeSet.toString())
db.insertOrThrow(HomeSets._TABLE, null, values)
}
}
fun saveCollections() {
db.delete(Collections._TABLE, "${HomeSets.SERVICE_ID}=?", arrayOf(service.toString()))
for ((_,collection) in collections) {
val values = collection.toDB()
Logger.log.log(Level.FINE, "Saving collection", values)
values.put(Collections.SERVICE_ID, service)
db.insertWithOnConflict(Collections._TABLE, null, values, SQLiteDatabase.CONFLICT_REPLACE)
}
}
try {
Logger.log.info("Refreshing $serviceType collections of service #$service")
Settings.getInstance(this)?.use { settings ->
// create authenticating OkHttpClient (credentials taken from account settings)
HttpClient.Builder(this, settings, AccountSettings(this, settings, 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")
queryHomeSets(httpClient, principalUrl)
}
// remember selected collections
val selectedCollections = HashSet<HttpUrl>()
collections.values
.filter { it.selected }
.forEach { (url, _) -> selectedCollections += url }
// 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")
try {
DavResource(httpClient, homeSetUrl).propfind(1, *CollectionInfo.DAV_PROPERTIES) { response, _ ->
if (!response.isSuccess())
return@propfind
val info = CollectionInfo(response)
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 && arrayOf(CollectionInfo.Type.CALENDAR, CollectionInfo.Type.WEBCAL).contains(info.type)))
collections[response.href] = info
}
} catch(e: HttpException) {
if (e.code 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)
try {
DavResource(httpClient, url).propfind(0, *CollectionInfo.DAV_PROPERTIES) { response, _ ->
if (!response.isSuccess())
return@propfind
val info = CollectionInfo(response)
info.confirmed = true
// remove unusable collections
if ((serviceType == Services.SERVICE_CARDDAV && info.type != CollectionInfo.Type.ADDRESS_BOOK) ||
(serviceType == Services.SERVICE_CALDAV && !arrayOf(CollectionInfo.Type.CALENDAR, CollectionInfo.Type.WEBCAL).contains(info.type)) ||
(info.type == CollectionInfo.Type.WEBCAL && info.source == null))
itCollections.remove()
}
} catch(e: HttpException) {
if (e.code 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 {
saveHomeSets()
saveCollections()
db.setTransactionSuccessful()
} finally {
db.endTransaction()
}
} catch(e: InvalidAccountException) {
Logger.log.log(Level.SEVERE, "Invalid account", e)
} catch(e: Exception) {
Logger.log.log(Level.SEVERE, "Couldn't refresh collection list", e)
val debugIntent = Intent(this, DebugInfoActivity::class.java)
debugIntent.putExtra(DebugInfoActivity.KEY_THROWABLE, e)
debugIntent.putExtra(DebugInfoActivity.KEY_ACCOUNT, account)
val notify = NotificationUtils.newBuilder(this)
.setSmallIcon(R.drawable.ic_sync_error_notification)
.setContentTitle(getString(R.string.dav_service_refresh_failed))
.setContentText(getString(R.string.dav_service_refresh_couldnt_refresh))
.setContentIntent(PendingIntent.getActivity(this, 0, debugIntent, PendingIntent.FLAG_UPDATE_CURRENT))
.setSubText(account.name)
.setCategory(NotificationCompat.CATEGORY_ERROR)
.build()
NotificationManagerCompat.from(this)
.notify(service.toString(), NotificationUtils.NOTIFY_REFRESH_COLLECTIONS, notify)
} finally {
runningRefresh.remove(service)
refreshingStatusListeners.forEach { it.get()?.onDavRefreshStatusChanged(service, false) }
}
}
}
}

View File

@@ -1,41 +0,0 @@
/*
* Copyright © 2013 2015 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.support.annotation.NonNull;
import org.apache.commons.lang3.StringUtils;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import okhttp3.HttpUrl;
public class DavUtils {
public static String ARGBtoCalDAVColor(int colorWithAlpha) {
byte alpha = (byte)(colorWithAlpha >> 24);
int color = colorWithAlpha & 0xFFFFFF;
return String.format("#%06X%02X", color, alpha);
}
public static String lastSegmentOfUrl(@NonNull String url) {
// the list returned by HttpUrl.pathSegments() is unmodifiable, so we have to create a copy
List<String> segments = new LinkedList<>(HttpUrl.parse(url).pathSegments());
Collections.reverse(segments);
for (String segment : segments)
if (!StringUtils.isEmpty(segment))
return segment;
return "/";
}
}

View File

@@ -0,0 +1,82 @@
/*
* 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.annotation.TargetApi
import android.content.Context
import android.net.ConnectivityManager
import android.os.Build
import at.bitfire.davdroid.log.Logger
import okhttp3.HttpUrl
import org.xbill.DNS.*
import java.util.*
/**
* Some WebDAV and related network utility methods
*/
object DavUtils {
fun ARGBtoCalDAVColor(colorWithAlpha: Int): String {
val alpha = (colorWithAlpha shr 24) and 0xFF
val color = colorWithAlpha and 0xFFFFFF
return String.format("#%06X%02X", color, alpha)
}
fun lastSegmentOfUrl(url: HttpUrl): String {
// the list returned by HttpUrl.pathSegments() is unmodifiable, so we have to create a copy
val segments = LinkedList<String>(url.pathSegments())
segments.reverse()
return segments.firstOrNull { it.isNotEmpty() } ?: "/"
}
fun prepareLookup(context: Context, lookup: Lookup) {
@TargetApi(Build.VERSION_CODES.O)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
/* Since Android 8, the system properties net.dns1, net.dns2, ... are not available anymore.
The current version of dnsjava relies on these properties to find the default name servers,
so we have to add the servers explicitly (fortunately, there's an Android API to
get the active DNS servers). */
val connectivity = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val activeLink = connectivity.getLinkProperties(connectivity.activeNetwork)
val simpleResolvers = activeLink.dnsServers.map {
Logger.log.fine("Using DNS server ${it.hostAddress}")
val resolver = SimpleResolver()
resolver.setAddress(it)
resolver
}
val resolver = ExtendedResolver(simpleResolvers.toTypedArray())
lookup.setResolver(resolver)
}
}
fun selectSRVRecord(records: Array<Record>?): SRVRecord? {
val srvRecords = records?.filterIsInstance(SRVRecord::class.java)
srvRecords?.let {
if (it.size > 1)
Logger.log.warning("Multiple SRV records not supported yet; using first one")
return it.firstOrNull()
}
return null
}
fun pathsFromTXTRecords(records: Array<Record>?): List<String> {
val paths = LinkedList<String>()
records?.filterIsInstance(TXTRecord::class.java)?.forEach { txt ->
@Suppress("UNCHECKED_CAST")
for (segment in txt.strings as List<String>)
if (segment.startsWith("path=")) {
paths.add(segment.substring(5))
break
}
}
return paths
}
}

View File

@@ -1,157 +0,0 @@
/*
* Copyright © 2013 2015 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.accounts.Account;
import android.content.Context;
import android.os.Build;
import android.support.annotation.NonNull;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import at.bitfire.dav4android.BasicDigestAuthenticator;
import lombok.RequiredArgsConstructor;
import okhttp3.Credentials;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.logging.HttpLoggingInterceptor;
public class HttpClient {
private static final OkHttpClient client = new OkHttpClient();
private static final UserAgentInterceptor userAgentInterceptor = new UserAgentInterceptor();
private static final String userAgent;
static {
String date = new SimpleDateFormat("yyyy/MM/dd", Locale.US).format(new Date(BuildConfig.buildTime));
userAgent = "DAVdroid/" + BuildConfig.VERSION_NAME + " (" + date + "; dav4android; okhttp3) Android/" + Build.VERSION.RELEASE;
}
private HttpClient() {
}
public static OkHttpClient create(@NonNull Context context, @NonNull Account account, @NonNull final Logger logger) throws InvalidAccountException {
OkHttpClient.Builder builder = defaultBuilder(logger);
// use account settings for authentication and logging
AccountSettings settings = new AccountSettings(context, account);
if (settings.preemptiveAuth())
builder.addNetworkInterceptor(new PreemptiveAuthenticationInterceptor(settings.username(), settings.password()));
else
builder.authenticator(new BasicDigestAuthenticator(null, settings.username(), settings.password()));
return builder.build();
}
public static OkHttpClient create(@NonNull Logger logger) {
return defaultBuilder(logger).build();
}
public static OkHttpClient create(@NonNull Context context, @NonNull Account account) throws InvalidAccountException {
return create(context, account, App.log);
}
public static OkHttpClient create() {
return create(App.log);
}
private static OkHttpClient.Builder defaultBuilder(@NonNull final Logger logger) {
OkHttpClient.Builder builder = client.newBuilder();
// use MemorizingTrustManager to manage self-signed certificates
if (App.getSslSocketFactoryCompat() != null)
builder.sslSocketFactory(App.getSslSocketFactoryCompat(), App.getMemorizingTrustManager());
if (App.getHostnameVerifier() != null)
builder.hostnameVerifier(App.getHostnameVerifier());
// 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);
// 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(new MemoryCookieStore());
// add network logging, if requested
if (logger.isLoggable(Level.FINEST)) {
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
@Override
public void log(String message) {
logger.finest(message);
}
});
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
builder.addInterceptor(loggingInterceptor);
}
return builder;
}
private static OkHttpClient.Builder addAuthentication(@NonNull OkHttpClient.Builder builder, @NonNull String username, @NonNull String password, boolean preemptive) {
if (preemptive)
builder.addNetworkInterceptor(new PreemptiveAuthenticationInterceptor(username, password));
else
builder.authenticator(new BasicDigestAuthenticator(null, username, password));
return builder;
}
public static OkHttpClient addAuthentication(@NonNull OkHttpClient client, @NonNull String username, @NonNull String password, boolean preemptive) {
OkHttpClient.Builder builder = client.newBuilder();
addAuthentication(builder, username, password, preemptive);
return builder.build();
}
public static OkHttpClient addAuthentication(@NonNull OkHttpClient client, @NonNull String host, @NonNull String username, @NonNull String password) {
return client.newBuilder()
.authenticator(new BasicDigestAuthenticator(host, username, password))
.build();
}
static class UserAgentInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Locale locale = Locale.getDefault();
Request request = chain.request().newBuilder()
.header("User-Agent", userAgent)
.header("Accept-Language", locale.getLanguage() + "-" + locale.getCountry() + ", " + locale.getLanguage() + ";q=0.7, *;q=0.5")
.build();
return chain.proceed(request);
}
}
@RequiredArgsConstructor
static class PreemptiveAuthenticationInterceptor implements Interceptor {
final String username, password;
@Override
public Response intercept(Chain chain) throws IOException {
App.log.fine("Adding basic authorization header for user " + username);
Request request = chain.request().newBuilder()
.header("Authorization", Credentials.basic(username, password))
.build();
return chain.proceed(request);
}
}
}

View File

@@ -0,0 +1,244 @@
/*
* 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 android.security.KeyChain
import at.bitfire.cert4android.CustomCertManager
import at.bitfire.dav4android.BasicDigestAuthHandler
import at.bitfire.dav4android.Constants
import at.bitfire.dav4android.UrlUtils
import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.model.Credentials
import at.bitfire.davdroid.settings.ISettings
import okhttp3.Cache
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.Response
import okhttp3.internal.tls.OkHostnameVerifier
import okhttp3.logging.HttpLoggingInterceptor
import java.io.File
import java.net.InetSocketAddress
import java.net.Proxy
import java.net.Socket
import java.security.KeyStore
import java.security.Principal
import java.text.SimpleDateFormat
import java.util.*
import java.util.concurrent.TimeUnit
import java.util.logging.Level
import javax.net.ssl.KeyManager
import javax.net.ssl.TrustManagerFactory
import javax.net.ssl.X509ExtendedKeyManager
import javax.net.ssl.X509TrustManager
class HttpClient private constructor(
val okHttpClient: OkHttpClient,
private val certManager: CustomCertManager?
): AutoCloseable {
companion object {
/** [OkHttpClient] singleton to build all clients from */
val sharedClient = OkHttpClient.Builder()
// set timeouts
.connectTimeout(15, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.readTimeout(120, TimeUnit.SECONDS)
// don't allow redirects by default, because it would break PROPFIND handling
.followRedirects(false)
// add User-Agent to every request
.addNetworkInterceptor(UserAgentInterceptor)
.build()!!
}
override fun close() {
certManager?.close()
}
class Builder(
val context: Context? = null,
val settings: ISettings? = null,
accountSettings: AccountSettings? = null,
val logger: java.util.logging.Logger = Logger.log
) {
private var certManager: CustomCertManager? = null
private var certificateAlias: String? = null
private val orig = sharedClient.newBuilder()
init {
// 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)
}
settings?.let {
// 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)
}
context?.let {
if (BuildConfig.customCerts)
customCertManager(CustomCertManager(context, BuildConfig.customCertsUI, !settings.getBoolean(App.DISTRUST_SYSTEM_CERTIFICATES, false)))
// use account settings for authentication
accountSettings?.let {
addAuthentication(null, it.credentials())
}
}
}
}
constructor(context: Context, host: String?, credentials: Credentials): this(context) {
addAuthentication(host, credentials)
}
fun withDiskCache(): Builder {
val context = context ?: throw IllegalArgumentException("Context is required to find the cache directory")
for (dir in arrayOf(context.externalCacheDir, context.cacheDir)) {
if (dir.exists() && dir.canWrite()) {
val cacheDir = File(dir, "HttpClient")
cacheDir.mkdir()
Logger.log.fine("Using disk cache: $cacheDir")
orig.cache(Cache(cacheDir, 10*1024*1024))
break
}
}
return this
}
fun followRedirects(follow: Boolean): Builder {
orig.followRedirects(follow)
return this
}
fun customCertManager(manager: CustomCertManager) {
certManager = manager
}
fun setForeground(foreground: Boolean): Builder {
certManager?.appInForeground = foreground
return this
}
fun addAuthentication(host: String?, credentials: Credentials): Builder {
when (credentials.type) {
Credentials.Type.UsernamePassword -> {
val authHandler = BasicDigestAuthHandler(UrlUtils.hostToDomain(host), credentials.userName!!, credentials.password!!)
orig .addNetworkInterceptor(authHandler)
.authenticator(authHandler)
}
Credentials.Type.ClientCertificate -> {
certificateAlias = credentials.certificateAlias
}
}
return this
}
fun build(): HttpClient {
val trustManager = certManager ?: {
val factory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
factory.init(null as KeyStore?)
factory.trustManagers.first() as X509TrustManager
}()
val hostnameVerifier = certManager?.hostnameVerifier(OkHostnameVerifier.INSTANCE)
?: OkHostnameVerifier.INSTANCE
var keyManager: KeyManager? = null
try {
certificateAlias?.let { alias ->
// get client certificate and private key
val certs = KeyChain.getCertificateChain(context, alias) ?: return@let
val key = KeyChain.getPrivateKey(context, alias) ?: return@let
logger.fine("Using client certificate $alias for authentication (chain length: ${certs.size})")
// create Android KeyStore (performs key operations without revealing secret data to DAVdroid)
val keyStore = KeyStore.getInstance("AndroidKeyStore")
keyStore.load(null)
// create KeyManager
keyManager = object: X509ExtendedKeyManager() {
override fun getServerAliases(p0: String?, p1: Array<out Principal>?): Array<String>? = null
override fun chooseServerAlias(p0: String?, p1: Array<out Principal>?, p2: Socket?) = null
override fun getClientAliases(p0: String?, p1: Array<out Principal>?) =
arrayOf(alias)
override fun chooseClientAlias(p0: Array<out String>?, p1: Array<out Principal>?, p2: Socket?) =
alias
override fun getCertificateChain(forAlias: String?) =
certs.takeIf { forAlias == alias }
override fun getPrivateKey(forAlias: String?) =
key.takeIf { forAlias == alias }
}
}
} catch (e: Exception) {
logger.log(Level.SEVERE, "Couldn't set up client certificate authentication", e)
}
orig.sslSocketFactory(CustomTlsSocketFactory(keyManager, trustManager), trustManager)
orig.hostnameVerifier(hostnameVerifier)
return HttpClient(orig.build(), certManager)
}
}
private object UserAgentInterceptor: Interceptor {
private val productName = when(BuildConfig.FLAVOR) {
App.FLAVOR_ICLOUD -> "MultiSync for Cloud"
App.FLAVOR_SOLDUPE -> "Soldupe Sync"
else -> "DAVdroid"
}
// use Locale.US because numbers may be encoded as non-ASCII characters in other locales
private val userAgentDateFormat = SimpleDateFormat("yyyy/MM/dd", Locale.US)
private val userAgentDate = userAgentDateFormat.format(Date(BuildConfig.buildTime))
private val userAgent = "$productName/${BuildConfig.VERSION_NAME} ($userAgentDate; dav4android; okhttp/${Constants.okHttpVersion}) Android/${Build.VERSION.RELEASE}"
override fun intercept(chain: Interceptor.Chain): Response {
val locale = Locale.getDefault()
val request = chain.request().newBuilder()
.header("User-Agent", userAgent)
.header("Accept-Language", "${locale.language}-${locale.country}, ${locale.language};q=0.7, *;q=0.5")
.build()
return chain.proceed(request)
}
}
}

View File

@@ -1,19 +0,0 @@
/*
* Copyright © 2013 2016 Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
*/
package at.bitfire.davdroid;
import android.accounts.Account;
public class InvalidAccountException extends Exception {
public InvalidAccountException(Account account) {
super("Invalid account: " + account);
}
}

View File

@@ -0,0 +1,13 @@
/*
* 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.accounts.Account
class InvalidAccountException(account: Account): Exception("Invalid account: $account")

View File

@@ -1,69 +0,0 @@
/*
* Copyright © 2013 2016 Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
*/
package at.bitfire.davdroid;
import org.apache.commons.collections4.MapIterator;
import org.apache.commons.collections4.keyvalue.MultiKey;
import org.apache.commons.collections4.map.HashedMap;
import org.apache.commons.collections4.map.MultiKeyMap;
import java.util.LinkedList;
import java.util.List;
import okhttp3.Cookie;
import okhttp3.CookieJar;
import okhttp3.HttpUrl;
/**
* Primitive cookie store that stores cookies in a (volatile) hash map.
* Will be sufficient for session cookies.
*/
public class MemoryCookieStore implements CookieJar {
/**
* Stored cookies. The multi-key consists of three parts: name, domain, and path.
* This ensures that cookies can be overwritten. [RFC 6265 5.3 Storage Model]
* Not thread-safe!
*/
protected final MultiKeyMap<String, Cookie> storage = MultiKeyMap.multiKeyMap(new HashedMap<MultiKey<? extends String>, Cookie>());
@Override
public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
synchronized(storage) {
for (Cookie cookie : cookies)
storage.put(cookie.name(), cookie.domain(), cookie.path(), cookie);
}
}
@Override
public List<Cookie> loadForRequest(HttpUrl url) {
List<Cookie> cookies = new LinkedList<>();
synchronized(storage) {
MapIterator<MultiKey<? extends String>, Cookie> iter = storage.mapIterator();
while (iter.hasNext()) {
iter.next();
Cookie cookie = iter.getValue();
// remove expired cookies
if (cookie.expiresAt() <= System.currentTimeMillis()) {
iter.remove();
continue;
}
// add applicable cookies
if (cookie.matches(url))
cookies.add(cookie);
}
}
return cookies;
}
}

View File

@@ -0,0 +1,63 @@
/*
* 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 okhttp3.Cookie
import okhttp3.CookieJar
import okhttp3.HttpUrl
import org.apache.commons.collections4.keyvalue.MultiKey
import org.apache.commons.collections4.map.HashedMap
import org.apache.commons.collections4.map.MultiKeyMap
import java.util.*
/**
* Primitive cookie store that stores cookies in a (volatile) hash map.
* Will be sufficient for session cookies.
*/
class MemoryCookieStore: CookieJar {
/**
* Stored cookies. The multi-key consists of three parts: name, domain, and path.
* This ensures that cookies can be overwritten. [RFC 6265 5.3 Storage Model]
* Not thread-safe!
*/
private val storage = MultiKeyMap.multiKeyMap(HashedMap<MultiKey<out String>, Cookie>())!!
override fun saveFromResponse(url: HttpUrl, cookies: List<Cookie>) {
synchronized(storage) {
for (cookie in cookies)
storage.put(cookie.name(), cookie.domain(), cookie.path(), cookie)
}
}
override fun loadForRequest(url: HttpUrl): List<Cookie> {
val cookies = LinkedList<Cookie>()
synchronized(storage) {
val iter = storage.mapIterator()
while (iter.hasNext()) {
iter.next()
val cookie = iter.value
// remove expired cookies
if (cookie.expiresAt() <= System.currentTimeMillis()) {
iter.remove()
continue
}
// add applicable cookies
if (cookie.matches(url))
cookies += cookie
}
}
return cookies
}
}

View File

@@ -0,0 +1,61 @@
/*
* 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.accounts.Account
import android.content.BroadcastReceiver
import android.content.ContentResolver
import android.content.Context
import android.content.Intent
import android.os.Bundle
import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.model.ServiceDB
import at.bitfire.davdroid.model.ServiceDB.Services
import at.bitfire.davdroid.resource.LocalTaskList
import at.bitfire.ical4android.TaskProvider
class PackageChangedReceiver: BroadcastReceiver() {
companion object {
fun updateTaskSync(context: Context) {
val tasksInstalled = LocalTaskList.tasksProviderAvailable(context)
Logger.log.info("Tasks provider available = $tasksInstalled")
// check all accounts and (de)activate OpenTasks if a CalDAV service is defined
ServiceDB.OpenHelper(context).use { dbHelper ->
val db = dbHelper.readableDatabase
db.query(Services._TABLE, arrayOf(Services.ACCOUNT_NAME),
"${Services.SERVICE}=?", arrayOf(Services.SERVICE_CALDAV), null, null, null)?.use { cursor ->
while (cursor.moveToNext()) {
val account = Account(cursor.getString(0), context.getString(R.string.account_type))
if (tasksInstalled) {
if (ContentResolver.getIsSyncable(account, TaskProvider.ProviderName.OpenTasks.authority) <= 0) {
ContentResolver.setIsSyncable(account, TaskProvider.ProviderName.OpenTasks.authority, 1)
ContentResolver.setSyncAutomatically(account, TaskProvider.ProviderName.OpenTasks.authority, true)
ContentResolver.addPeriodicSync(account, TaskProvider.ProviderName.OpenTasks.authority, Bundle(), Constants.DEFAULT_SYNC_INTERVAL)
}
} else
ContentResolver.setIsSyncable(account, TaskProvider.ProviderName.OpenTasks.authority, 0)
}
}
}
}
}
override fun onReceive(context: Context, intent: Intent) {
updateTaskSync(context)
}
}

View File

@@ -1,171 +0,0 @@
/*
* Copyright © 2013 2015 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.os.Build;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.security.GeneralSecurityException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.X509TrustManager;
import de.duenndns.ssl.MemorizingTrustManager;
import lombok.Cleanup;
public class SSLSocketFactoryCompat extends SSLSocketFactory {
private SSLSocketFactory delegate;
// Android 5.0+ (API level21) provides reasonable default settings
// but it still allows SSLv3
// https://developer.android.com/reference/javax/net/ssl/SSLSocket.html
static String protocols[] = null, cipherSuites[] = null;
static {
try {
@Cleanup SSLSocket socket = (SSLSocket)SSLSocketFactory.getDefault().createSocket();
if (socket != null) {
/* set reasonable protocol versions */
// - enable all supported protocols (enables TLSv1.1 and TLSv1.2 on Android <5.0)
// - remove all SSL versions (especially SSLv3) because they're insecure now
List<String> protocols = new LinkedList<>();
for (String protocol : socket.getSupportedProtocols())
if (!protocol.toUpperCase(Locale.US).contains("SSL"))
protocols.add(protocol);
App.log.info("Setting allowed TLS protocols: " + TextUtils.join(", ", protocols));
SSLSocketFactoryCompat.protocols = protocols.toArray(new String[protocols.size()]);
/* set up reasonable cipher suites */
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
// choose known secure cipher suites
List<String> allowedCiphers = Arrays.asList(
// TLS 1.2
"TLS_RSA_WITH_AES_256_GCM_SHA384",
"TLS_RSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
// maximum interoperability
"TLS_RSA_WITH_3DES_EDE_CBC_SHA",
"TLS_RSA_WITH_AES_128_CBC_SHA",
// additionally
"TLS_RSA_WITH_AES_256_CBC_SHA",
"TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA");
List<String> availableCiphers = Arrays.asList(socket.getSupportedCipherSuites());
App.log.info("Available cipher suites: " + TextUtils.join(", ", availableCiphers));
App.log.info("Cipher suites enabled by default: " + TextUtils.join(", ", socket.getEnabledCipherSuites()));
// take all allowed ciphers that are available and put them into preferredCiphers
HashSet<String> preferredCiphers = new HashSet<>(allowedCiphers);
preferredCiphers.retainAll(availableCiphers);
/* For maximum security, preferredCiphers should *replace* enabled ciphers (thus disabling
* ciphers which are enabled by default, but have become unsecure), but I guess for
* the security level of DAVdroid and maximum compatibility, disabling of insecure
* ciphers should be a server-side task */
// add preferred ciphers to enabled ciphers
HashSet<String> enabledCiphers = preferredCiphers;
enabledCiphers.addAll(new HashSet<>(Arrays.asList(socket.getEnabledCipherSuites())));
App.log.info("Enabling (only) those TLS ciphers: " + TextUtils.join(", ", enabledCiphers));
SSLSocketFactoryCompat.cipherSuites = enabledCiphers.toArray(new String[enabledCiphers.size()]);
}
}
} catch (IOException e) {
App.log.severe("Couldn't determine default TLS settings");
}
}
public SSLSocketFactoryCompat(@NonNull MemorizingTrustManager mtm) {
try {
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new X509TrustManager[] { mtm }, null);
delegate = sslContext.getSocketFactory();
} catch (GeneralSecurityException e) {
throw new AssertionError(); // The system has no TLS. Just give up.
}
}
private void upgradeTLS(SSLSocket ssl) {
if (protocols != null)
ssl.setEnabledProtocols(protocols);
if (cipherSuites != null)
ssl.setEnabledCipherSuites(cipherSuites);
}
@Override
public String[] getDefaultCipherSuites() {
return cipherSuites;
}
@Override
public String[] getSupportedCipherSuites() {
return cipherSuites;
}
@Override
public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
Socket ssl = delegate.createSocket(s, host, port, autoClose);
if (ssl instanceof SSLSocket)
upgradeTLS((SSLSocket)ssl);
return ssl;
}
@Override
public Socket createSocket(String host, int port) throws IOException {
Socket ssl = delegate.createSocket(host, port);
if (ssl instanceof SSLSocket)
upgradeTLS((SSLSocket)ssl);
return ssl;
}
@Override
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException {
Socket ssl = delegate.createSocket(host, port, localHost, localPort);
if (ssl instanceof SSLSocket)
upgradeTLS((SSLSocket)ssl);
return ssl;
}
@Override
public Socket createSocket(InetAddress host, int port) throws IOException {
Socket ssl = delegate.createSocket(host, port);
if (ssl instanceof SSLSocket)
upgradeTLS((SSLSocket)ssl);
return ssl;
}
@Override
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
Socket ssl = delegate.createSocket(address, port, localAddress, localPort);
if (ssl instanceof SSLSocket)
upgradeTLS((SSLSocket)ssl);
return ssl;
}
}

View File

@@ -1,59 +0,0 @@
/*
* Copyright © 2013 2016 Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
*/
package at.bitfire.davdroid.log;
import android.util.Log;
import org.apache.commons.lang3.math.NumberUtils;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
public class LogcatHandler extends Handler {
private static final int MAX_LINE_LENGTH = 3000;
public static final LogcatHandler INSTANCE = new LogcatHandler();
private LogcatHandler() {
super();
setFormatter(PlainTextFormatter.LOGCAT);
setLevel(Level.ALL);
}
@Override
public void publish(LogRecord r) {
String text = getFormatter().format(r);
int level = r.getLevel().intValue();
int end = text.length();
for (int pos = 0; pos < end; pos += MAX_LINE_LENGTH) {
String line = text.substring(pos, NumberUtils.min(pos + MAX_LINE_LENGTH, end));
if (level >= Level.SEVERE.intValue())
Log.e(r.getLoggerName(), line);
else if (level >= Level.WARNING.intValue())
Log.w(r.getLoggerName(), line);
else if (level >= Level.CONFIG.intValue())
Log.i(r.getLoggerName(), line);
else if (level >= Level.FINER.intValue())
Log.d(r.getLoggerName(), line);
else
Log.v(r.getLoggerName(), line);
}
}
@Override
public void flush() {
}
@Override
public void close() {
}
}

View File

@@ -0,0 +1,50 @@
/*
* 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.log
import android.util.Log
import org.apache.commons.lang3.math.NumberUtils
import java.util.logging.Handler
import java.util.logging.Level
import java.util.logging.LogRecord
object LogcatHandler: Handler() {
private const val MAX_LINE_LENGTH = 3000
init {
formatter = PlainTextFormatter.LOGCAT
level = Level.ALL
}
override fun publish(r: LogRecord) {
val text = formatter.format(r)
val level = r.level.intValue()
val end = text.length
var pos = 0
while (pos < end) {
val line = text.substring(pos, NumberUtils.min(pos + MAX_LINE_LENGTH, end))
when {
level >= Level.SEVERE.intValue() -> Log.e(r.loggerName, line)
level >= Level.WARNING.intValue() -> Log.w(r.loggerName, line)
level >= Level.CONFIG.intValue() -> Log.i(r.loggerName, line)
level >= Level.FINER.intValue() -> Log.d(r.loggerName, line)
else -> Log.v(r.loggerName, line)
}
pos += MAX_LINE_LENGTH
}
}
override fun flush() {}
override fun close() {}
}

View File

@@ -0,0 +1,106 @@
/*
* 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.log
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.os.Process
import android.preference.PreferenceManager
import android.support.v4.app.NotificationCompat
import android.support.v4.app.NotificationManagerCompat
import android.util.Log
import at.bitfire.davdroid.R
import at.bitfire.davdroid.ui.AppSettingsActivity
import at.bitfire.davdroid.ui.NotificationUtils
import org.apache.commons.lang3.time.DateFormatUtils
import java.io.File
import java.io.IOException
import java.util.logging.FileHandler
import java.util.logging.Level
object Logger {
const val LOG_TO_EXTERNAL_STORAGE = "log_to_external_storage"
val log = java.util.logging.Logger.getLogger("davdroid")!!
private lateinit var preferences: SharedPreferences
fun initialize(context: Context) {
preferences = PreferenceManager.getDefaultSharedPreferences(context)
preferences.registerOnSharedPreferenceChangeListener { _, s ->
if (s == LOG_TO_EXTERNAL_STORAGE)
reinitialize(context.applicationContext)
}
reinitialize(context.applicationContext)
}
private fun reinitialize(context: Context) {
val logToFile = preferences.getBoolean(LOG_TO_EXTERNAL_STORAGE, false)
val logVerbose = logToFile || Log.isLoggable(log.name, Log.DEBUG)
log.info("Verbose logging: $logVerbose; to file: $logToFile")
// set logging level according to preferences
val rootLogger = java.util.logging.Logger.getLogger("")
rootLogger.level = if (logVerbose) Level.ALL else Level.INFO
// remove all handlers and add our own logcat handler
rootLogger.useParentHandlers = false
rootLogger.handlers.forEach { rootLogger.removeHandler(it) }
rootLogger.addHandler(LogcatHandler)
val nm = NotificationManagerCompat.from(context)
// log to external file according to preferences
if (logToFile) {
val builder = NotificationUtils.newBuilder(context, NotificationUtils.CHANNEL_DEBUG)
builder .setSmallIcon(R.drawable.ic_sd_storage_notification)
.setContentTitle(context.getString(R.string.logging_davdroid_file_logging))
.setLocalOnly(true)
val dir = context.getExternalFilesDir(null)
if (dir != null)
try {
val fileName = File(dir, "davdroid-${Process.myPid()}-${DateFormatUtils.format(System.currentTimeMillis(), "yyyyMMdd-HHmmss")}.txt").toString()
log.info("Logging to $fileName")
val fileHandler = FileHandler(fileName)
fileHandler.formatter = PlainTextFormatter.DEFAULT
rootLogger.addHandler(fileHandler)
val prefIntent = Intent(context, AppSettingsActivity::class.java)
prefIntent.putExtra(AppSettingsActivity.EXTRA_SCROLL_TO, LOG_TO_EXTERNAL_STORAGE)
builder .setContentText(dir.path)
.setCategory(NotificationCompat.CATEGORY_STATUS)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setContentIntent(PendingIntent.getActivity(context, 0, prefIntent, PendingIntent.FLAG_UPDATE_CURRENT))
.setStyle(NotificationCompat.BigTextStyle().bigText(context.getString(R.string.logging_to_external_storage, dir.path)))
.setOngoing(true)
} catch(e: IOException) {
log.log(Level.SEVERE, "Couldn't create external log file", e)
val message = context.getString(R.string.logging_couldnt_create_file, e.localizedMessage)
builder .setContentText(message)
.setStyle(NotificationCompat.BigTextStyle().bigText(message))
.setCategory(NotificationCompat.CATEGORY_ERROR)
}
else
builder.setContentText(context.getString(R.string.logging_no_external_storage))
nm.notify(NotificationUtils.NOTIFY_EXTERNAL_FILE_LOGGING, builder.build())
} else
nm.cancel(NotificationUtils.NOTIFY_EXTERNAL_FILE_LOGGING)
}
}

View File

@@ -1,61 +0,0 @@
/*
* Copyright © 2013 2016 Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
*/
package at.bitfire.davdroid.log;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import java.util.logging.Formatter;
import java.util.logging.LogRecord;
public class PlainTextFormatter extends Formatter {
public final static PlainTextFormatter
LOGCAT = new PlainTextFormatter(true),
DEFAULT = new PlainTextFormatter(false);
private final boolean logcat;
private PlainTextFormatter(boolean onLogcat) {
this.logcat = onLogcat;
}
@Override
@SuppressWarnings("ThrowableResultOfMethodCallIgnored")
public String format(LogRecord r) {
StringBuilder builder = new StringBuilder();
if (!logcat)
builder .append(DateFormatUtils.format(r.getMillis(), "yyyy-MM-dd HH:mm:ss"))
.append(" ").append(r.getThreadID()).append(" ");
builder.append(String.format("[%s] %s", shortClassName(r.getSourceClassName()), r.getMessage()));
if (r.getThrown() != null)
builder .append("\nEXCEPTION ")
.append(ExceptionUtils.getStackTrace(r.getThrown()));
if (r.getParameters() != null) {
int idx = 1;
for (Object param : r.getParameters())
builder.append("\n\tPARAMETER #").append(idx++).append(" = ").append(param);
}
if (!logcat)
builder.append("\n");
return builder.toString();
}
private String shortClassName(String className) {
String s = StringUtils.replace(className, "at.bitfire.davdroid.", "");
return StringUtils.replace(s, "at.bitfire.", "");
}
}

View File

@@ -0,0 +1,61 @@
/*
* 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.log
import org.apache.commons.lang3.StringUtils
import org.apache.commons.lang3.exception.ExceptionUtils
import org.apache.commons.lang3.time.DateFormatUtils
import java.util.logging.Formatter
import java.util.logging.LogRecord
class PlainTextFormatter private constructor(
private val logcat: Boolean
): Formatter() {
companion object {
val LOGCAT = PlainTextFormatter(true)
val DEFAULT = PlainTextFormatter(false)
const val MAX_MESSAGE_LENGTH = 20000
}
override fun format(r: LogRecord): String {
val builder = StringBuilder()
if (!logcat)
builder .append(DateFormatUtils.format(r.millis, "yyyy-MM-dd HH:mm:ss"))
.append(" ").append(r.threadID).append(" ")
val className = shortClassName(r.sourceClassName)
if (className != r.loggerName)
builder.append("[").append(className).append("] ")
builder.append(StringUtils.abbreviate(r.message, MAX_MESSAGE_LENGTH))
r.thrown?.let {
builder .append("\nEXCEPTION ")
.append(ExceptionUtils.getStackTrace(it))
}
r.parameters?.let {
for ((idx, param) in it.withIndex())
builder.append("\n\tPARAMETER #").append(idx).append(" = ").append(param)
}
if (!logcat)
builder.append("\n")
return builder.toString()
}
private fun shortClassName(className: String) = className
.replace(Regex("^at\\.bitfire\\.(dav|cert4an|dav4an|ical4an|vcard4an)droid\\."), "")
.replace(Regex("\\$.*$"), "")
}

View File

@@ -1,40 +0,0 @@
/*
* Copyright © 2013 2016 Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
*/
package at.bitfire.davdroid.log;
import java.util.logging.Handler;
import java.util.logging.LogRecord;
public class StringHandler extends Handler {
StringBuilder builder = new StringBuilder();
public StringHandler() {
super();
setFormatter(PlainTextFormatter.DEFAULT);
}
@Override
public void publish(LogRecord record) {
builder.append(getFormatter().format(record));
}
@Override
public void flush() {
}
@Override
public void close() {
}
@Override
public String toString() {
return builder.toString();
}
}

View File

@@ -0,0 +1,31 @@
/*
* 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.log
import java.util.logging.Handler
import java.util.logging.LogRecord
class StringHandler: Handler() {
val builder = StringBuilder()
init {
formatter = PlainTextFormatter.DEFAULT
}
override fun publish(record: LogRecord) {
builder.append(formatter.format(record))
}
override fun flush() {}
override fun close() {}
override fun toString() = builder.toString()
}

View File

@@ -1,163 +0,0 @@
/*
* Copyright © 2013 2016 Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
*/
package at.bitfire.davdroid.model;
import android.content.ContentValues;
import org.apache.commons.lang3.StringUtils;
import java.io.Serializable;
import at.bitfire.dav4android.DavResource;
import at.bitfire.dav4android.Property;
import at.bitfire.dav4android.property.AddressbookDescription;
import at.bitfire.dav4android.property.CalendarColor;
import at.bitfire.dav4android.property.CalendarDescription;
import at.bitfire.dav4android.property.CalendarTimezone;
import at.bitfire.dav4android.property.CurrentUserPrivilegeSet;
import at.bitfire.dav4android.property.DisplayName;
import at.bitfire.dav4android.property.ResourceType;
import at.bitfire.dav4android.property.SupportedAddressData;
import at.bitfire.dav4android.property.SupportedCalendarComponentSet;
import at.bitfire.davdroid.model.ServiceDB.Collections;
import lombok.ToString;
@ToString
public class CollectionInfo implements Serializable {
public long id;
public Long serviceID;
public enum Type {
ADDRESS_BOOK,
CALENDAR
}
public Type type;
public String url;
public boolean readOnly;
public String displayName, description;
public Integer color;
public String timeZone;
public Boolean supportsVEVENT;
public Boolean supportsVTODO;
public boolean selected;
// non-persistent properties
public boolean confirmed;
public static final Property.Name[] DAV_PROPERTIES = {
ResourceType.NAME,
CurrentUserPrivilegeSet.NAME,
DisplayName.NAME,
AddressbookDescription.NAME, SupportedAddressData.NAME,
CalendarDescription.NAME, CalendarColor.NAME, SupportedCalendarComponentSet.NAME
};
public static CollectionInfo fromDavResource(DavResource dav) {
CollectionInfo info = new CollectionInfo();
info.url = dav.location.toString();
ResourceType type = (ResourceType)dav.properties.get(ResourceType.NAME);
if (type != null) {
if (type.types.contains(ResourceType.ADDRESSBOOK))
info.type = Type.ADDRESS_BOOK;
else if (type.types.contains(ResourceType.CALENDAR))
info.type = Type.CALENDAR;
}
info.readOnly = false;
CurrentUserPrivilegeSet privilegeSet = (CurrentUserPrivilegeSet)dav.properties.get(CurrentUserPrivilegeSet.NAME);
if (privilegeSet != null)
info.readOnly = !privilegeSet.mayWriteContent;
DisplayName displayName = (DisplayName)dav.properties.get(DisplayName.NAME);
if (displayName != null && !StringUtils.isEmpty(displayName.displayName))
info.displayName = displayName.displayName;
if (info.type == Type.ADDRESS_BOOK) {
AddressbookDescription addressbookDescription = (AddressbookDescription)dav.properties.get(AddressbookDescription.NAME);
if (addressbookDescription != null)
info.description = addressbookDescription.description;
} else if (info.type == Type.CALENDAR) {
CalendarDescription calendarDescription = (CalendarDescription)dav.properties.get(CalendarDescription.NAME);
if (calendarDescription != null)
info.description = calendarDescription.description;
CalendarColor calendarColor = (CalendarColor)dav.properties.get(CalendarColor.NAME);
if (calendarColor != null)
info.color = calendarColor.color;
CalendarTimezone timeZone = (CalendarTimezone)dav.properties.get(CalendarTimezone.NAME);
if (timeZone != null)
info.timeZone = timeZone.vTimeZone;
info.supportsVEVENT = info.supportsVTODO = true;
SupportedCalendarComponentSet supportedCalendarComponentSet = (SupportedCalendarComponentSet)dav.properties.get(SupportedCalendarComponentSet.NAME);
if (supportedCalendarComponentSet != null) {
info.supportsVEVENT = supportedCalendarComponentSet.supportsEvents;
info.supportsVTODO = supportedCalendarComponentSet.supportsTasks;
}
}
return info;
}
public static CollectionInfo fromDB(ContentValues values) {
CollectionInfo info = new CollectionInfo();
info.id = values.getAsLong(Collections.ID);
info.serviceID = values.getAsLong(Collections.SERVICE_ID);
info.url = values.getAsString(Collections.URL);
info.readOnly = values.getAsInteger(Collections.READ_ONLY) != 0;
info.displayName = values.getAsString(Collections.DISPLAY_NAME);
info.description = values.getAsString(Collections.DESCRIPTION);
info.color = values.getAsInteger(Collections.COLOR);
info.timeZone = values.getAsString(Collections.TIME_ZONE);
info.supportsVEVENT = getAsBooleanOrNull(values, Collections.SUPPORTS_VEVENT);
info.supportsVTODO = getAsBooleanOrNull(values, Collections.SUPPORTS_VTODO);
info.selected = values.getAsInteger(Collections.SYNC) != 0;
return info;
}
public ContentValues toDB() {
ContentValues values = new ContentValues();
// Collections.SERVICE_ID is never changed
values.put(Collections.URL, url);
values.put(Collections.READ_ONLY, readOnly ? 1 : 0);
values.put(Collections.DISPLAY_NAME, displayName);
values.put(Collections.DESCRIPTION, description);
values.put(Collections.COLOR, color);
values.put(Collections.TIME_ZONE, timeZone);
if (supportsVEVENT != null)
values.put(Collections.SUPPORTS_VEVENT, supportsVEVENT ? 1 : 0);
if (supportsVTODO != null)
values.put(Collections.SUPPORTS_VTODO, supportsVTODO ? 1 : 0);
values.put(Collections.SYNC, selected ? 1 : 0);
return values;
}
private static Boolean getAsBooleanOrNull(ContentValues values, String field) {
Integer i = values.getAsInteger(field);
return (i == null) ? null : (i != 0);
}
}

View File

@@ -0,0 +1,251 @@
/*
* 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.model
import android.content.ContentValues
import android.os.Parcel
import android.os.Parcelable
import at.bitfire.dav4android.Response
import at.bitfire.dav4android.UrlUtils
import at.bitfire.dav4android.property.*
import at.bitfire.davdroid.model.ServiceDB.Collections
import okhttp3.HttpUrl
/**
* Represents a WebDAV collection.
*
* @constructor always appends a trailing slash to the URL
*/
data class CollectionInfo(
/**
* URL of the collection (including trailing slash)
*/
val url: HttpUrl,
var id: Long? = null,
var serviceID: Long? = null,
var type: Type? = null,
var privWriteContent: Boolean = true,
var privUnbind: Boolean = true,
var forceReadOnly: Boolean = false,
var displayName: String? = null,
var description: String? = null,
var color: Int? = null,
var timeZone: String? = null,
var supportsVEVENT: Boolean = false,
var supportsVTODO: Boolean = false,
var selected: Boolean = false,
// subscriptions
var source: String? = null,
// non-persistent properties
var confirmed: Boolean = false
): Parcelable {
enum class Type {
ADDRESS_BOOK,
CALENDAR,
WEBCAL // iCalendar subscription
}
constructor(dav: Response): this(UrlUtils.withTrailingSlash(dav.href)) {
dav[ResourceType::class.java]?.let { type ->
when {
type.types.contains(ResourceType.ADDRESSBOOK) -> this.type = Type.ADDRESS_BOOK
type.types.contains(ResourceType.CALENDAR) -> this.type = Type.CALENDAR
type.types.contains(ResourceType.SUBSCRIBED) -> this.type = Type.WEBCAL
}
}
dav[CurrentUserPrivilegeSet::class.java]?.let { privilegeSet ->
privWriteContent = privilegeSet.mayWriteContent
privUnbind = privilegeSet.mayUnbind
}
dav[DisplayName::class.java]?.let {
if (!it.displayName.isNullOrEmpty())
displayName = it.displayName
}
when (type) {
Type.ADDRESS_BOOK -> {
dav[AddressbookDescription::class.java]?.let { description = it.description }
}
Type.CALENDAR, Type.WEBCAL -> {
dav[CalendarDescription::class.java]?.let { description = it.description }
dav[CalendarColor::class.java]?.let { color = it.color }
dav[CalendarTimezone::class.java]?.let { timeZone = it.vTimeZone }
if (type == Type.CALENDAR) {
supportsVEVENT = true
supportsVTODO = true
dav[SupportedCalendarComponentSet::class.java]?.let {
supportsVEVENT = it.supportsEvents
supportsVTODO = it.supportsTasks
}
} else { // Type.WEBCAL
dav[Source::class.java]?.let { source = it.hrefs.firstOrNull() }
supportsVEVENT = true
}
}
}
}
constructor(values: ContentValues): this(UrlUtils.withTrailingSlash(HttpUrl.parse(values.getAsString(Collections.URL))!!)) {
id = values.getAsLong(Collections.ID)
serviceID = values.getAsLong(Collections.SERVICE_ID)
type = try {
Type.valueOf(values.getAsString(Collections.TYPE))
} catch (e: Exception) {
null
}
privWriteContent = values.getAsInteger(Collections.PRIV_WRITE_CONTENT) != 0
privUnbind = values.getAsInteger(Collections.PRIV_UNBIND) != 0
forceReadOnly = values.getAsInteger(Collections.FORCE_READ_ONLY) != 0
displayName = values.getAsString(Collections.DISPLAY_NAME)
description = values.getAsString(Collections.DESCRIPTION)
color = values.getAsInteger(Collections.COLOR)
timeZone = values.getAsString(Collections.TIME_ZONE)
supportsVEVENT = getAsBooleanOrNull(values, Collections.SUPPORTS_VEVENT) ?: false
supportsVTODO = getAsBooleanOrNull(values, Collections.SUPPORTS_VTODO) ?: false
source = values.getAsString(Collections.SOURCE)
selected = values.getAsInteger(Collections.SYNC) != 0
}
fun toDB(): ContentValues {
val values = ContentValues()
// Collections.SERVICE_ID is never changed
type?.let { values.put(Collections.TYPE, it.name) }
values.put(Collections.URL, url.toString())
values.put(Collections.PRIV_WRITE_CONTENT, if (privWriteContent) 1 else 0)
values.put(Collections.PRIV_UNBIND, if (privUnbind) 1 else 0)
values.put(Collections.FORCE_READ_ONLY, if (forceReadOnly) 1 else 0)
values.put(Collections.DISPLAY_NAME, displayName)
values.put(Collections.DESCRIPTION, description)
values.put(Collections.COLOR, color)
values.put(Collections.TIME_ZONE, timeZone)
values.put(Collections.SUPPORTS_VEVENT, if (supportsVEVENT) 1 else 0)
values.put(Collections.SUPPORTS_VTODO, if (supportsVTODO) 1 else 0)
values.put(Collections.SOURCE, source)
values.put(Collections.SYNC, if (selected) 1 else 0)
return values
}
private fun getAsBooleanOrNull(values: ContentValues, field: String): Boolean? {
val i = values.getAsInteger(field)
return if (i == null)
null
else
(i != 0)
}
override fun describeContents(): Int = 0
override fun writeToParcel(dest: Parcel, flags: Int) {
fun<T> writeOrNull(value: T?, write: (T) -> Unit) {
if (value == null)
dest.writeByte(0)
else {
dest.writeByte(1)
write(value)
}
}
dest.writeString(url.toString())
writeOrNull(id) { dest.writeLong(it) }
writeOrNull(serviceID) { dest.writeLong(it) }
dest.writeString(type?.name)
dest.writeByte(if (privWriteContent) 1 else 0)
dest.writeByte(if (privUnbind) 1 else 0)
dest.writeByte(if (forceReadOnly) 1 else 0)
dest.writeString(displayName)
dest.writeString(description)
writeOrNull(color) { dest.writeInt(it) }
dest.writeString(timeZone)
dest.writeByte(if (supportsVEVENT) 1 else 0)
dest.writeByte(if (supportsVTODO) 1 else 0)
dest.writeByte(if (selected) 1 else 0)
dest.writeString(source)
dest.writeByte(if (confirmed) 1 else 0)
}
companion object CREATOR : Parcelable.Creator<CollectionInfo> {
val DAV_PROPERTIES = arrayOf(
ResourceType.NAME,
CurrentUserPrivilegeSet.NAME,
DisplayName.NAME,
AddressbookDescription.NAME, SupportedAddressData.NAME,
CalendarDescription.NAME, CalendarColor.NAME, SupportedCalendarComponentSet.NAME,
Source.NAME
)
override fun createFromParcel(parcel: Parcel): CollectionInfo {
fun<T> readOrNull(parcel: Parcel, read: () -> T): T? {
return if (parcel.readByte() == 0.toByte())
null
else
read()
}
return CollectionInfo(
HttpUrl.parse(parcel.readString())!!,
readOrNull(parcel) { parcel.readLong() },
readOrNull(parcel) { parcel.readLong() },
parcel.readString()?.let { Type.valueOf(it) },
parcel.readByte() != 0.toByte(),
parcel.readByte() != 0.toByte(),
parcel.readByte() != 0.toByte(),
parcel.readString(),
parcel.readString(),
readOrNull(parcel) { parcel.readInt() },
parcel.readString(),
parcel.readByte() != 0.toByte(),
parcel.readByte() != 0.toByte(),
parcel.readByte() != 0.toByte(),
parcel.readString(),
parcel.readByte() != 0.toByte()
)
}
override fun newArray(size: Int) = arrayOfNulls<CollectionInfo>(size)
}
}

View File

@@ -0,0 +1,40 @@
/*
* 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.model
import java.io.Serializable
class Credentials(
val userName: String? = null,
val password: String? = null,
val certificateAlias: String? = null
): Serializable {
enum class Type {
UsernamePassword,
ClientCertificate
}
val type: Type
init {
type = when {
!certificateAlias.isNullOrEmpty() ->
Type.ClientCertificate
!userName.isNullOrEmpty() && !password.isNullOrEmpty() ->
Type.UsernamePassword
else ->
throw IllegalArgumentException("Either username/password or certificate alias must be set")
}
}
override fun toString() =
"Credentials(type=$type, userName=$userName, certificateAlias=$certificateAlias)"
}

View File

@@ -1,186 +0,0 @@
/*
* Copyright © 2013 2016 Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
*/
package at.bitfire.davdroid.model;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Build;
import at.bitfire.davdroid.App;
import lombok.Cleanup;
public class ServiceDB {
public static class Settings {
public static final String
_TABLE = "settings",
NAME = "setting",
VALUE = "value";
}
public static class Services {
public static final String
_TABLE = "services",
ID = "_id",
ACCOUNT_NAME = "accountName",
SERVICE = "service",
PRINCIPAL = "principal";
// allowed values for SERVICE column
public static final String
SERVICE_CALDAV = "caldav",
SERVICE_CARDDAV = "carddav";
}
public static class HomeSets {
public static final String
_TABLE = "homesets",
ID = "_id",
SERVICE_ID = "serviceID",
URL = "url";
}
public static class Collections {
public static final String
_TABLE = "collections",
ID = "_id",
SERVICE_ID = "serviceID",
URL = "url",
READ_ONLY = "readOnly",
DISPLAY_NAME = "displayName",
DESCRIPTION = "description",
COLOR = "color",
TIME_ZONE = "timezone",
SUPPORTS_VEVENT = "supportsVEVENT",
SUPPORTS_VTODO = "supportsVTODO",
SYNC = "sync";
}
public static class OpenHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "services.db";
private static final int DATABASE_VERSION = 1;
public OpenHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)
setWriteAheadLoggingEnabled(true);
}
@Override
public void onOpen(SQLiteDatabase db) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)
db.setForeignKeyConstraintsEnabled(true);
else {
if (!db.enableWriteAheadLogging())
App.log.warning("Couldn't enable write-ahead logging");
db.execSQL("PRAGMA foreign_keys=ON;");
}
}
@Override
public void onCreate(SQLiteDatabase db) {
App.log.info("Creating database " + db.getPath());
db.execSQL("CREATE TABLE " + Settings._TABLE + "(" +
Settings.NAME + " TEXT NOT NULL," +
Settings.VALUE + " TEXT NOT NULL" +
")");
db.execSQL("CREATE UNIQUE INDEX settings_name ON " + Settings._TABLE + " (" + Settings.NAME + ")");
db.execSQL("CREATE TABLE " + Services._TABLE + "(" +
Services.ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
Services.ACCOUNT_NAME + " TEXT NOT NULL," +
Services.SERVICE + " TEXT NOT NULL," +
Services.PRINCIPAL + " TEXT NULL" +
")");
db.execSQL("CREATE UNIQUE INDEX services_account ON " + Services._TABLE + " (" + Services.ACCOUNT_NAME + "," + Services.SERVICE + ")");
db.execSQL("CREATE TABLE " + HomeSets._TABLE + "(" +
HomeSets.ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
HomeSets.SERVICE_ID + " INTEGER NOT NULL REFERENCES " + Services._TABLE +" ON DELETE CASCADE," +
HomeSets.URL + " TEXT NOT NULL" +
")");
db.execSQL("CREATE UNIQUE INDEX homesets_service_url ON " + HomeSets._TABLE + "(" + HomeSets.SERVICE_ID + "," + HomeSets.URL + ")");
db.execSQL("CREATE TABLE " + Collections._TABLE + "(" +
Collections.ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
Collections.SERVICE_ID + " INTEGER NOT NULL REFERENCES " + Services._TABLE +" ON DELETE CASCADE," +
Collections.URL + " TEXT NOT NULL," +
Collections.READ_ONLY + " INTEGER DEFAULT 0 NOT NULL," +
Collections.DISPLAY_NAME + " TEXT NULL," +
Collections.DESCRIPTION + " TEXT NULL," +
Collections.COLOR + " INTEGER NULL," +
Collections.TIME_ZONE + " TEXT NULL," +
Collections.SUPPORTS_VEVENT + " INTEGER NULL," +
Collections.SUPPORTS_VTODO + " INTEGER NULL," +
Collections.SYNC + " INTEGER DEFAULT 0 NOT NULL" +
")");
db.execSQL("CREATE UNIQUE INDEX collections_service_url ON " + Collections._TABLE + "(" + Collections.SERVICE_ID + "," + Collections.URL + ")");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
public void dump(StringBuilder sb) {
SQLiteDatabase db = getReadableDatabase();
db.beginTransactionNonExclusive();
// iterate through all tables
@Cleanup Cursor cursorTables = db.query("sqlite_master", new String[] { "name" }, "type='table'", null, null, null, null);
while (cursorTables.moveToNext()) {
String table = cursorTables.getString(0);
sb.append(table).append("\n");
@Cleanup Cursor cursor = db.query(table, null, null, null, null, null, null);
// print columns
int cols = cursor.getColumnCount();
sb.append("\t| ");
for (int i = 0; i < cols; i++) {
sb.append(" ");
sb.append(cursor.getColumnName(i));
sb.append(" |");
}
sb.append("\n");
// print rows
while (cursor.moveToNext()) {
sb.append("\t| ");
for (int i = 0; i < cols; i++) {
sb.append(" ");
try {
String value = cursor.getString(i);
if (value != null)
sb.append(value
.replace("\r", "<CR>")
.replace("\n", "<LF>"));
else
sb.append("<null>");
} catch (SQLiteException e) {
sb.append("<unprintable>");
}
sb.append(" |");
}
sb.append("\n");
}
sb.append("----------\n");
}
db.endTransaction();
}
}
}

View File

@@ -0,0 +1,236 @@
/*
* 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.model
import android.content.ContentValues
import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteException
import android.database.sqlite.SQLiteOpenHelper
import android.preference.PreferenceManager
import at.bitfire.davdroid.App
import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.ui.StartupDialogFragment
import java.util.logging.Level
class ServiceDB {
object Services {
const val _TABLE = "services"
const val ID = "_id"
const val ACCOUNT_NAME = "accountName"
const val SERVICE = "service"
const val PRINCIPAL = "principal"
// allowed values for SERVICE column
const val SERVICE_CALDAV = "caldav"
const val SERVICE_CARDDAV = "carddav"
}
object HomeSets {
const val _TABLE = "homesets"
const val ID = "_id"
const val SERVICE_ID = "serviceID"
const val URL = "url"
}
object Collections {
const val _TABLE = "collections"
const val ID = "_id"
const val TYPE = "type"
const val SERVICE_ID = "serviceID"
const val URL = "url"
const val PRIV_WRITE_CONTENT = "privWriteContent"
const val PRIV_UNBIND = "privUnbind"
const val FORCE_READ_ONLY = "forceReadOnly"
const val DISPLAY_NAME = "displayName"
const val DESCRIPTION = "description"
const val COLOR = "color"
const val TIME_ZONE = "timezone"
const val SUPPORTS_VEVENT = "supportsVEVENT"
const val SUPPORTS_VTODO = "supportsVTODO"
const val SOURCE = "source"
const val SYNC = "sync"
}
companion object {
fun onRenameAccount(db: SQLiteDatabase, oldName: String, newName: String) {
val values = ContentValues(1)
values.put(Services.ACCOUNT_NAME, newName)
db.updateWithOnConflict(Services._TABLE, values, Services.ACCOUNT_NAME + "=?", arrayOf(oldName), SQLiteDatabase.CONFLICT_REPLACE)
}
}
class OpenHelper(
val context: Context
): SQLiteOpenHelper(context, DATABASE_NAME, null, DATABASE_VERSION), AutoCloseable {
companion object {
const val DATABASE_NAME = "services.db"
const val DATABASE_VERSION = 5
}
override fun onConfigure(db: SQLiteDatabase) {
setWriteAheadLoggingEnabled(true)
db.setForeignKeyConstraintsEnabled(true)
}
override fun onCreate(db: SQLiteDatabase) {
Logger.log.info("Creating database " + db.path)
db.execSQL("CREATE TABLE ${Services._TABLE}(" +
"${Services.ID} INTEGER PRIMARY KEY AUTOINCREMENT," +
"${Services.ACCOUNT_NAME} TEXT NOT NULL," +
"${Services.SERVICE} TEXT NOT NULL," +
"${Services.PRINCIPAL} TEXT NULL)")
db.execSQL("CREATE UNIQUE INDEX services_account ON ${Services._TABLE} (${Services.ACCOUNT_NAME},${Services.SERVICE})")
db.execSQL("CREATE TABLE ${HomeSets._TABLE}(" +
"${HomeSets.ID} INTEGER PRIMARY KEY AUTOINCREMENT," +
"${HomeSets.SERVICE_ID} INTEGER NOT NULL REFERENCES ${Services._TABLE} ON DELETE CASCADE," +
"${HomeSets.URL} TEXT NOT NULL)")
db.execSQL("CREATE UNIQUE INDEX homesets_service_url ON ${HomeSets._TABLE}(${HomeSets.SERVICE_ID},${HomeSets.URL})")
db.execSQL("CREATE TABLE ${Collections._TABLE}(" +
"${Collections.ID} INTEGER PRIMARY KEY AUTOINCREMENT," +
"${Collections.SERVICE_ID} INTEGER NOT NULL REFERENCES ${Services._TABLE} ON DELETE CASCADE," +
"${Collections.TYPE} TEXT NOT NULL," +
"${Collections.URL} TEXT NOT NULL," +
"${Collections.PRIV_WRITE_CONTENT} INTEGER DEFAULT 0 NOT NULL," +
"${Collections.PRIV_UNBIND} INTEGER DEFAULT 0 NOT NULL," +
"${Collections.FORCE_READ_ONLY} INTEGER DEFAULT 0 NOT NULL," +
"${Collections.DISPLAY_NAME} TEXT NULL," +
"${Collections.DESCRIPTION} TEXT NULL," +
"${Collections.COLOR} INTEGER NULL," +
"${Collections.TIME_ZONE} TEXT NULL," +
"${Collections.SUPPORTS_VEVENT} INTEGER NULL," +
"${Collections.SUPPORTS_VTODO} INTEGER NULL," +
"${Collections.SOURCE} TEXT NULL," +
"${Collections.SYNC} INTEGER DEFAULT 0 NOT NULL)")
db.execSQL("CREATE UNIQUE INDEX collections_service_url ON ${Collections._TABLE}(${Collections.SERVICE_ID},${Collections.URL})")
}
override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
for (upgradeFrom in oldVersion until newVersion) {
val upgradeTo = upgradeFrom + 1
Logger.log.info("Upgrading database from version $upgradeFrom to $upgradeTo")
try {
val upgradeProc = this::class.java.getDeclaredMethod("upgrade_${upgradeFrom}_$upgradeTo", SQLiteDatabase::class.java)
upgradeProc.invoke(this, db)
} catch(e: Exception) {
Logger.log.log(Level.SEVERE, "Couldn't upgrade database", e)
}
}
}
@Suppress("unused")
private fun upgrade_4_5(db: SQLiteDatabase) {
db.execSQL("ALTER TABLE ${Collections._TABLE} ADD COLUMN ${Collections.PRIV_WRITE_CONTENT} INTEGER DEFAULT 0 NOT NULL")
db.execSQL("UPDATE ${Collections._TABLE} SET ${Collections.PRIV_WRITE_CONTENT}=NOT readOnly")
db.execSQL("ALTER TABLE ${Collections._TABLE} ADD COLUMN ${Collections.PRIV_UNBIND} INTEGER DEFAULT 0 NOT NULL")
db.execSQL("UPDATE ${Collections._TABLE} SET ${Collections.PRIV_UNBIND}=NOT readOnly")
// there's no DROP COLUMN in SQLite, so just keep the "readOnly" column
}
@Suppress("unused")
private fun upgrade_3_4(db: SQLiteDatabase) {
db.execSQL("ALTER TABLE ${Collections._TABLE} ADD COLUMN ${Collections.FORCE_READ_ONLY} INTEGER DEFAULT 0 NOT NULL")
}
@Suppress("unused")
private fun upgrade_2_3(db: SQLiteDatabase) {
val edit = PreferenceManager.getDefaultSharedPreferences(context).edit()
try {
db.query("settings", arrayOf("setting", "value"), null, null, null, null, null).use { cursor ->
while (cursor.moveToNext()) {
when (cursor.getString(0)) {
"distrustSystemCerts" -> edit.putBoolean(App.DISTRUST_SYSTEM_CERTIFICATES, cursor.getInt(1) != 0)
"overrideProxy" -> edit.putBoolean(App.OVERRIDE_PROXY, cursor.getInt(1) != 0)
"overrideProxyHost" -> edit.putString(App.OVERRIDE_PROXY_HOST, cursor.getString(1))
"overrideProxyPort" -> edit.putInt(App.OVERRIDE_PROXY_PORT, cursor.getInt(1))
StartupDialogFragment.HINT_GOOGLE_PLAY_ACCOUNTS_REMOVED ->
edit.putBoolean(StartupDialogFragment.HINT_GOOGLE_PLAY_ACCOUNTS_REMOVED, cursor.getInt(1) != 0)
StartupDialogFragment.HINT_OPENTASKS_NOT_INSTALLED ->
edit.putBoolean(StartupDialogFragment.HINT_OPENTASKS_NOT_INSTALLED, cursor.getInt(1) != 0)
}
}
}
db.execSQL("DROP TABLE settings")
} finally {
edit.apply()
}
}
@Suppress("unused")
private fun upgrade_1_2(db: SQLiteDatabase) {
db.execSQL("ALTER TABLE ${Collections._TABLE} ADD COLUMN ${Collections.TYPE} TEXT NOT NULL DEFAULT ''")
db.execSQL("ALTER TABLE ${Collections._TABLE} ADD COLUMN ${Collections.SOURCE} TEXT NULL")
db.execSQL("UPDATE ${Collections._TABLE} SET ${Collections.TYPE}=(" +
"SELECT CASE ${Services.SERVICE} WHEN ? THEN ? ELSE ? END " +
"FROM ${Services._TABLE} WHERE ${Services.ID}=${Collections._TABLE}.${Collections.SERVICE_ID}" +
")",
arrayOf(Services.SERVICE_CALDAV, CollectionInfo.Type.CALENDAR, CollectionInfo.Type.ADDRESS_BOOK))
}
fun dump(sb: StringBuilder) {
val db = readableDatabase
db.beginTransactionNonExclusive()
// iterate through all tables
db.query("sqlite_master", arrayOf("name"), "type='table'", null, null, null, null).use { cursorTables ->
while (cursorTables.moveToNext()) {
val table = cursorTables.getString(0)
sb.append(table).append("\n")
db.query(table, null, null, null, null, null, null).use { cursor ->
// print columns
val cols = cursor.columnCount
sb.append("\t| ")
for (i in 0 until cols)
sb .append(" ")
.append(cursor.getColumnName(i))
.append(" |")
sb.append("\n")
// print rows
while (cursor.moveToNext()) {
sb.append("\t| ")
for (i in 0 until cols) {
sb.append(" ")
try {
val value = cursor.getString(i)
if (value != null)
sb.append(value
.replace("\r", "<CR>")
.replace("\n", "<LF>"))
else
sb.append("<null>")
} catch (e: SQLiteException) {
sb.append("<unprintable>")
}
sb.append(" |")
}
sb.append("\n")
}
sb.append("----------\n")
}
}
db.endTransaction()
}
}
}
}

View File

@@ -1,45 +0,0 @@
/*
* Copyright © 2013 2016 Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
*/
package at.bitfire.davdroid.model;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import lombok.Cleanup;
public class Settings {
final SQLiteDatabase db;
public Settings(SQLiteDatabase db) {
this.db = db;
}
public boolean getBoolean(String name, boolean defaultValue) {
@Cleanup Cursor cursor = db.query(ServiceDB.Settings._TABLE, new String[] { ServiceDB.Settings.VALUE },
ServiceDB.Settings.NAME + "=?", new String[] { name }, null, null, null);
if (cursor.moveToNext())
return cursor.getInt(0) != 0;
else
return defaultValue;
}
public void putBoolean(String name, boolean value) {
ContentValues values = new ContentValues(2);
values.put(ServiceDB.Settings.NAME, name);
values.put(ServiceDB.Settings.VALUE, value ? 1 : 0);
db.insertWithOnConflict(ServiceDB.Settings._TABLE, null, values, SQLiteDatabase.CONFLICT_REPLACE);
}
public void remove(String name) {
db.delete(ServiceDB.Settings._TABLE, ServiceDB.Settings.NAME + "=?", new String[] { name });
}
}

View File

@@ -0,0 +1,63 @@
/*
* 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.model
import at.bitfire.dav4android.property.SyncToken
import org.json.JSONException
import org.json.JSONObject
data class SyncState(
val type: Type,
val value: String,
/**
* Whether this sync state occurred during an initial sync as described
* in RFC 6578, which means the initial sync is not complete yet.
*/
var initialSync: Boolean? = null
) {
companion object {
private const val KEY_TYPE = "type"
private const val KEY_VALUE = "value"
private const val KEY_INITIAL_SYNC = "initialSync"
fun fromString(s: String?): SyncState? {
if (s == null)
return null
return try {
val json = JSONObject(s)
SyncState(
Type.valueOf(json.getString(KEY_TYPE)),
json.getString(KEY_VALUE),
try { json.getBoolean(KEY_INITIAL_SYNC) } catch(e: JSONException) { null }
)
} catch (e: JSONException) {
null
}
}
fun fromSyncToken(token: SyncToken, initialSync: Boolean? = null) =
SyncState(Type.SYNC_TOKEN, requireNotNull(token.token), initialSync)
}
enum class Type { CTAG, SYNC_TOKEN }
override fun toString(): String {
val json = JSONObject()
json.put(KEY_TYPE, type.name)
json.put(KEY_VALUE, value)
initialSync?.let { json.put(KEY_INITIAL_SYNC, it) }
return json.toString()
}
}

View File

@@ -1,22 +0,0 @@
/*
* Copyright © 2013 2016 Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
*/
package at.bitfire.davdroid.model;
import android.provider.ContactsContract.RawContacts;
public class UnknownProperties {
public static final String CONTENT_ITEM_TYPE = "x.davdroid/unknown-properties";
public static final String
MIMETYPE = RawContacts.Data.MIMETYPE,
RAW_CONTACT_ID = RawContacts.Data.RAW_CONTACT_ID,
UNKNOWN_PROPERTIES = RawContacts.Data.DATA1;
}

View File

@@ -0,0 +1,21 @@
/*
* 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.model
import android.provider.ContactsContract.RawContacts
object UnknownProperties {
const val CONTENT_ITEM_TYPE = "x.davdroid/unknown-properties"
const val MIMETYPE = RawContacts.Data.MIMETYPE
const val RAW_CONTACT_ID = RawContacts.Data.RAW_CONTACT_ID
const val UNKNOWN_PROPERTIES = RawContacts.Data.DATA1
}

Some files were not shown because too many files have changed in this diff Show More