├── .gitignore ├── ACalDAV ├── .gitignore ├── AndroidManifest.xml ├── _gradle.properties ├── build.gradle ├── ic_gmail-web.png ├── ic_launcher-web.png ├── proguard-project.txt ├── res │ ├── drawable-hdpi │ │ ├── ic_gmail.png │ │ └── icon.png │ ├── drawable-mdpi │ │ ├── ic_gmail.png │ │ └── icon.png │ ├── drawable-xhdpi │ │ ├── ic_gmail.png │ │ └── icon.png │ ├── drawable-xxhdpi │ │ └── icon.png │ ├── drawable │ │ └── icon.png │ ├── layout │ │ └── activity_authenticator.xml │ ├── values-de │ │ └── strings.xml │ ├── values-it │ │ └── strings.xml │ ├── values-large │ │ └── styles.xml │ ├── values-v11 │ │ └── styles.xml │ ├── values-v14 │ │ └── styles.xml │ ├── values │ │ ├── strings.xml │ │ └── styles.xml │ └── xml │ │ ├── authenticator.xml │ │ └── syncadapter.xml └── src │ ├── de │ └── we │ │ └── acaldav │ │ ├── App.java │ │ ├── utilities │ │ └── AccountUtility.java │ │ └── widget │ │ ├── DrawableClickListener.java │ │ └── IconfiedEditText.java │ └── org │ └── gege │ └── caldavsyncadapter │ ├── CalendarColors.java │ ├── Constants.java │ ├── Event.java │ ├── android │ └── entities │ │ └── AndroidEvent.java │ ├── authenticator │ ├── AuthenticationService.java │ ├── AuthenticatorActivity.java │ └── AuthenticatorStub.java │ ├── caldav │ ├── CaldavFacade.java │ ├── CaldavProtocolException.java │ ├── EasySSLSocketFactory.java │ ├── EasyX509TrustManager.java │ ├── TlsSniSocketFactory.java │ ├── discovery │ │ ├── DefaultDiscoveryStrategy.java │ │ ├── DiscoveryStrategy.java │ │ └── GoogleDiscoveryStrategy.java │ ├── entities │ │ ├── CalendarEvent.java │ │ ├── CalendarList.java │ │ └── DavCalendar.java │ ├── http │ │ ├── HttpDelete.java │ │ ├── HttpPropFind.java │ │ ├── HttpPut.java │ │ └── HttpReport.java │ └── xml │ │ ├── CalendarHomeHandler.java │ │ ├── CalendarsHandler.java │ │ ├── MultiStatusHandler.java │ │ ├── ServerInfoHandler.java │ │ └── sax │ │ ├── MultiStatus.java │ │ ├── Prop.java │ │ ├── PropStat.java │ │ └── Response.java │ └── syncadapter │ ├── SyncAdapter.java │ ├── SyncService.java │ └── notifications │ └── NotificationsHelper.java ├── LICENSE ├── README.md ├── build.gradle ├── config └── quality │ ├── checkstyle │ ├── checkstyle-suppressions.xml │ ├── checkstyle.xml │ ├── checkstyle.xsl │ └── checkstyle_QA.xml │ ├── findbugs │ ├── findbugs-filter-exclude.xml │ └── findbugs-filter-include.xml │ ├── pmd │ ├── pmd-configuration.xml │ ├── pmd-ruleset.xml │ └── rulesets │ │ ├── android.xml │ │ └── basic.xml │ └── quality.gradle └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.orig 2 | build/ 3 | local.properties 4 | *.iml 5 | .idea 6 | .navigation 7 | buildQuality.gradle_ 8 | aCalDAV/gradle.properties 9 | wait_for_emulator 10 | resources 11 | .gradle/ 12 | gradle/ 13 | gradlew 14 | gradlew.bat -------------------------------------------------------------------------------- /ACalDAV/.gitignore: -------------------------------------------------------------------------------- 1 | proguard/ 2 | *.iml 3 | market 4 | build.gradle -------------------------------------------------------------------------------- /ACalDAV/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 24 | 27 | 28 | 29 | 30 | 31 | 34 | 35 | 38 | 39 | 40 | 41 | 42 | 45 | 46 | 47 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /ACalDAV/_gradle.properties: -------------------------------------------------------------------------------- 1 | myStoreFile= 2 | myStorePassword= 3 | myKeyPassword= 4 | myKeyAlias= -------------------------------------------------------------------------------- /ACalDAV/build.gradle: -------------------------------------------------------------------------------- 1 | import com.android.builder.core.DefaultManifestParser 2 | 3 | apply plugin: 'com.android.application' 4 | apply from: '../config/quality/quality.gradle' 5 | 6 | android { 7 | compileSdkVersion 22 8 | buildToolsVersion '22.0.0' 9 | 10 | compileOptions { 11 | sourceCompatibility JavaVersion.VERSION_1_7 12 | targetCompatibility JavaVersion.VERSION_1_7 13 | } 14 | 15 | sourceSets { 16 | main { 17 | manifest.srcFile 'AndroidManifest.xml' 18 | java.srcDirs = ['src'] 19 | resources.srcDirs = ['src'] 20 | aidl.srcDirs = ['src'] 21 | renderscript.srcDirs = ['src'] 22 | res.srcDirs = ['res'] 23 | assets.srcDirs = ['assets'] 24 | } 25 | 26 | } 27 | 28 | defaultConfig { 29 | applicationId "de.we.acaldav" 30 | minSdkVersion 14 31 | targetSdkVersion 20 32 | multiDexEnabled true 33 | 34 | def manifestParser = new DefaultManifestParser() 35 | versionName = manifestParser.getVersionName(android.sourceSets.main.manifest.srcFile) 36 | } 37 | 38 | signingConfigs { 39 | //noinspection GroovyMissingReturnStatement 40 | release { 41 | if (project.hasProperty('myKeyAlias') && 42 | project.hasProperty('myStoreFile') && 43 | project.hasProperty('myStorePassword') && 44 | project.hasProperty('myKeyPassword')) { 45 | keyAlias = myKeyAlias 46 | storeFile = file(myStoreFile) 47 | storePassword = myStorePassword 48 | keyPassword = myKeyPassword 49 | } 50 | } 51 | } 52 | 53 | buildTypes { 54 | 55 | release { 56 | minifyEnabled true 57 | signingConfig signingConfigs.release 58 | proguardFile 'proguard-project.txt' 59 | } 60 | 61 | debug { 62 | //noinspection GroovyAssignabilityCheck 63 | applicationIdSuffix = ".debug" 64 | //noinspection GroovyAssignabilityCheck 65 | versionNameSuffix = "-DEBUG" 66 | } 67 | 68 | //noinspection GroovyAssignabilityCheck 69 | applicationVariants.all { variant -> 70 | variant.outputs.each { output -> 71 | output.outputFile = new File(output.outputFile.parent, output.outputFile.name.replace(".apk", "-" + defaultConfig.versionName + ".apk")) 72 | } 73 | } 74 | } 75 | 76 | packagingOptions { 77 | exclude 'META-INF/LICENSE.txt' 78 | exclude 'META-INF/NOTICE.txt' 79 | } 80 | 81 | } 82 | 83 | dependencies { 84 | compile 'com.android.support:support-v4:22.0.0' 85 | compile 'backport-util-concurrent:backport-util-concurrent:3.1' 86 | compile 'commons-codec:commons-codec:1.10' 87 | compile 'org.apache.commons:commons-lang3:3.3.2' 88 | compile 'org.mnode.ical4j:ical4j:1.0.6' 89 | repositories { 90 | mavenCentral() 91 | } 92 | } 93 | 94 | buildscript { 95 | repositories { 96 | mavenCentral() 97 | } 98 | 99 | dependencies { 100 | classpath 'com.android.tools.build:gradle:1.5.0' 101 | } 102 | } 103 | 104 | -------------------------------------------------------------------------------- /ACalDAV/ic_gmail-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ennswi/AndroidCaldavSyncAdapater/649190265c47622a013e218025c2f10b31d24f93/ACalDAV/ic_gmail-web.png -------------------------------------------------------------------------------- /ACalDAV/ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ennswi/AndroidCaldavSyncAdapater/649190265c47622a013e218025c2f10b31d24f93/ACalDAV/ic_launcher-web.png -------------------------------------------------------------------------------- /ACalDAV/proguard-project.txt: -------------------------------------------------------------------------------- 1 | # To enable ProGuard in your project, edit project.properties 2 | # to define the proguard.config property as described in that file. 3 | # 4 | # Add project specific ProGuard rules here. 5 | # By default, the flags in this file are appended to flags specified 6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt 7 | # You can edit the include path and order by changing the ProGuard 8 | # include property in project.properties. 9 | # 10 | # For more details, see 11 | # http://developer.android.com/guide/developing/tools/proguard.html 12 | 13 | # Add any project specific keep options here: 14 | -verbose 15 | 16 | -optimizations !class/unboxing/enum 17 | #-dontobfuscate 18 | 19 | -assumenosideeffects class android.util.Log { 20 | public static *** d(...); 21 | public static *** v(...); 22 | } 23 | 24 | -dontwarn android.support.v4.** 25 | 26 | #-keep class android.support.v4.** { *; } 27 | 28 | -dontwarn org.apache.** 29 | -dontwarn sun.** 30 | -dontwarn net.fortuna.ical4j.** 31 | 32 | 33 | # If your project uses WebView with JS, uncomment the following 34 | # and specify the fully qualified class name to the JavaScript interface 35 | # class: 36 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 37 | # public *; 38 | #} 39 | -------------------------------------------------------------------------------- /ACalDAV/res/drawable-hdpi/ic_gmail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ennswi/AndroidCaldavSyncAdapater/649190265c47622a013e218025c2f10b31d24f93/ACalDAV/res/drawable-hdpi/ic_gmail.png -------------------------------------------------------------------------------- /ACalDAV/res/drawable-hdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ennswi/AndroidCaldavSyncAdapater/649190265c47622a013e218025c2f10b31d24f93/ACalDAV/res/drawable-hdpi/icon.png -------------------------------------------------------------------------------- /ACalDAV/res/drawable-mdpi/ic_gmail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ennswi/AndroidCaldavSyncAdapater/649190265c47622a013e218025c2f10b31d24f93/ACalDAV/res/drawable-mdpi/ic_gmail.png -------------------------------------------------------------------------------- /ACalDAV/res/drawable-mdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ennswi/AndroidCaldavSyncAdapater/649190265c47622a013e218025c2f10b31d24f93/ACalDAV/res/drawable-mdpi/icon.png -------------------------------------------------------------------------------- /ACalDAV/res/drawable-xhdpi/ic_gmail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ennswi/AndroidCaldavSyncAdapater/649190265c47622a013e218025c2f10b31d24f93/ACalDAV/res/drawable-xhdpi/ic_gmail.png -------------------------------------------------------------------------------- /ACalDAV/res/drawable-xhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ennswi/AndroidCaldavSyncAdapater/649190265c47622a013e218025c2f10b31d24f93/ACalDAV/res/drawable-xhdpi/icon.png -------------------------------------------------------------------------------- /ACalDAV/res/drawable-xxhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ennswi/AndroidCaldavSyncAdapater/649190265c47622a013e218025c2f10b31d24f93/ACalDAV/res/drawable-xxhdpi/icon.png -------------------------------------------------------------------------------- /ACalDAV/res/drawable/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ennswi/AndroidCaldavSyncAdapater/649190265c47622a013e218025c2f10b31d24f93/ACalDAV/res/drawable/icon.png -------------------------------------------------------------------------------- /ACalDAV/res/layout/activity_authenticator.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 15 | 16 | 21 | 22 | 30 | 31 | 32 | 33 | 34 | 38 | 39 | 44 | 45 | 54 | 55 | 56 | 57 | 58 | 59 | 71 | 72 | 80 | 81 | 89 | 90 | 100 | 101 | 110 | 111 | 121 | 122 | 128 | 129 | 130 | 131 | 132 | -------------------------------------------------------------------------------- /ACalDAV/res/values-de/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Einstellungen 4 | 5 | Anmelden 6 | 7 | 8 | Benutzer 9 | Passwort 10 | Accountname (optional) 11 | Aktualisierungintervall (Minuten) 12 | Anmelden oder registrieren 13 | Anmelden 14 | Hinweis: Der Accountname wird auch als Emailadresse des Organisators verwendet. 15 | Passwort wiederherstellen 16 | Teste Verbindung… 17 | Diese E-Mail Adresse ist ungültig 18 | Das Passwort ist zu kurz 19 | Das Passwort ist falsch 20 | Dieses Feld wird benötigt 21 | URL 22 | Das Format der URL ist falsch 23 | Ungültige Server Antwort, URL überprüfen 24 | Falsche URL 25 | Verbindungsaufbau verweigert 26 | Die ist keine gültige Zahl 27 | Unbekannter Fehler 28 | Account bereits in Verwendung 29 | Verbindung erfolgreich (Kalender) 30 | Verbindung erfolgreich (mehrere Kalender) 31 | Überprüfe SSL Zertifikat 32 | SSL Fehler 33 | Nicht vertrauenswürdiges Zertifikat 34 | 35 | -------------------------------------------------------------------------------- /ACalDAV/res/values-it/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | aCalDAV 4 | Entra o registrati 5 | Nota: il nome del profilo è anche usato come e-mail dell\'organizzatore. 6 | Login 7 | Profilo già presente 8 | Connessione rifiutata 9 | Questo campo è richiesto 10 | La password è sbagliata 11 | Il formato dell\'URL non è corretto 12 | Questo indirizzo e-mail non è valido 13 | Questo non è un numero valido 14 | La password è troppo corta 15 | Risposta server non valida 16 | Errore SSL 17 | Errore sconosciuto 18 | Certificato non fidato 19 | URL errato 20 | Provo la connessione… 21 | Ho perso la password 22 | Impostazioni 23 | Nome profilo (opzionale) 24 | Password 25 | Intervallo aggiornamento (minuti) 26 | URL 27 | Utente 28 | Connessione effettuata (calendario) 29 | Connessione effettuata (più di un calendario) 30 | Accedi 31 | Controlla il certificato SSL 32 | Errore sincronizzazione (CalDaV) 33 | Errore sincronizzazione (generale) 34 | Errore sincronizzazione (IO) 35 | Errore sincronizzazione (parsing) 36 | Errore sincronizzazione (provider) 37 | Errore sincronizzazione (SSL) 38 | stai usando CyanogenMod in modalità Incognito? 39 | Il provider non è riuscito a prendere o creare un nuovo profilo 40 | Errore sincronizzazione CalDAV 41 | -------------------------------------------------------------------------------- /ACalDAV/res/values-large/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | -------------------------------------------------------------------------------- /ACalDAV/res/values-v11/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /ACalDAV/res/values-v14/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /ACalDAV/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | aCalDAV 5 | aCalDAV 6 | Settings 7 | aCalDAV Sync Status 8 | 9 | 10 | Sign in 11 | 12 | 13 | User 14 | Password 15 | Account name (optional) 16 | Update interval (minutes) 17 | Sign in or register 18 | Login 19 | Note: The account name is also used as an email address of the organizer. 20 | Recover lost password 21 | Testing connection… 22 | This email address is invalid 23 | This password is too short 24 | This password is incorrect 25 | This field is required 26 | URL 27 | The format of the URL is wrong 28 | Invalid server answer, check URL 29 | Wrong URL 30 | Connection refused 31 | This is not a valid number 32 | Unknown error 33 | Account already added 34 | SSL error 35 | Connection success (calendar) 36 | Connection success (multiple calendars) 37 | Check SSL Certificate 38 | Untrusted certificate 39 | Caldav sync error (provider failed) 40 | are you using CyanogenMod in Incognito Mode? 41 | the provider failed to get an existing or create a new calendar 42 | Caldav sync error (SSL) 43 | Caldav sync error (IO) 44 | Caldav sync error (parsing) 45 | Caldav sync error (general) 46 | Caldav sync error (CalDAV) 47 | Caldav sync problem 48 | 49 | -------------------------------------------------------------------------------- /ACalDAV/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 15 | 16 | 17 | 20 | 21 | 26 | 27 | -------------------------------------------------------------------------------- /ACalDAV/res/xml/authenticator.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 21 | 26 | -------------------------------------------------------------------------------- /ACalDAV/res/xml/syncadapter.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /ACalDAV/src/de/we/acaldav/App.java: -------------------------------------------------------------------------------- 1 | package de.we.acaldav; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | 6 | /** 7 | * @author Joseph Weigl 8 | */ 9 | public class App extends Application { 10 | 11 | private static Context mContext; 12 | 13 | public App() { 14 | super(); 15 | App.mContext = this; 16 | } 17 | 18 | public static Context getContext() { 19 | return mContext; 20 | } 21 | 22 | public static void setContext(Context context) { 23 | mContext = context; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /ACalDAV/src/de/we/acaldav/utilities/AccountUtility.java: -------------------------------------------------------------------------------- 1 | package de.we.acaldav.utilities; 2 | 3 | import android.accounts.Account; 4 | import android.accounts.AccountManager; 5 | 6 | import de.we.acaldav.App; 7 | 8 | /** 9 | * @author Joseph Weigl 10 | */ 11 | public class AccountUtility { 12 | 13 | /** 14 | * Private constructor for utility class 15 | */ 16 | private AccountUtility() { 17 | // nothing to do 18 | } 19 | 20 | /** 21 | * Returns all available Google accounts 22 | * 23 | * @return array of google accounts. Empty (never null) if no accounts of the specified type have been added. 24 | */ 25 | public static Account[] getGoogleAccounts() { 26 | Account[] accounts = AccountManager.get(App.getContext()).getAccountsByType("com.google"); 27 | return accounts; 28 | } 29 | 30 | /** 31 | * Returns the email of the first found Google account or an empty string 32 | * 33 | * @return google email address or an empty string 34 | */ 35 | public static String getGoogleMail() { 36 | Account[] accounts = getGoogleAccounts(); 37 | if (accounts.length > 0) { 38 | return accounts[0].name; 39 | } else return ""; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /ACalDAV/src/de/we/acaldav/widget/DrawableClickListener.java: -------------------------------------------------------------------------------- 1 | package de.we.acaldav.widget; 2 | 3 | /** 4 | * @author Joseph Weigl 5 | */ 6 | public interface DrawableClickListener { 7 | 8 | public void onClick(DrawablePosition target); 9 | 10 | public static enum DrawablePosition {TOP, BOTTOM, LEFT, RIGHT} 11 | } 12 | -------------------------------------------------------------------------------- /ACalDAV/src/de/we/acaldav/widget/IconfiedEditText.java: -------------------------------------------------------------------------------- 1 | package de.we.acaldav.widget; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.Rect; 6 | import android.graphics.drawable.Drawable; 7 | import android.text.Editable; 8 | import android.text.TextUtils; 9 | import android.text.TextWatcher; 10 | import android.util.AttributeSet; 11 | import android.view.MotionEvent; 12 | import android.widget.EditText; 13 | 14 | /** 15 | * @author Joseph Weigl 16 | */ 17 | public class IconfiedEditText extends EditText { 18 | 19 | int actionX, actionY; 20 | private Drawable drawableRight; 21 | private Drawable drawableLeft; 22 | private Drawable drawableTop; 23 | private Drawable drawableBottom; 24 | private DrawableClickListener clickListener; 25 | 26 | private Drawable mClearButton; 27 | 28 | @SuppressWarnings("UnusedDeclaration") 29 | public IconfiedEditText(Context context, AttributeSet attrs) { 30 | super(context, attrs); 31 | // this Contructure required when you are using this view in xml 32 | } 33 | 34 | @SuppressWarnings("UnusedDeclaration") 35 | public IconfiedEditText(Context context, AttributeSet attrs, int defStyle) { 36 | super(context, attrs, defStyle); 37 | } 38 | 39 | protected void onDraw(Canvas canvas) { 40 | super.onDraw(canvas); 41 | 42 | } 43 | 44 | @Override 45 | protected void onSizeChanged(int w, int h, int oldw, int oldh) { 46 | setHeight(h); 47 | super.onSizeChanged(w, h, oldw, oldh); 48 | } 49 | 50 | @Override 51 | public void setCompoundDrawables(Drawable left, Drawable top, 52 | Drawable right, Drawable bottom) { 53 | if (left != null) { 54 | drawableLeft = left; 55 | } 56 | if (right != null) { 57 | drawableRight = right; 58 | } 59 | if (top != null) { 60 | drawableTop = top; 61 | } 62 | if (bottom != null) { 63 | drawableBottom = bottom; 64 | } 65 | super.setCompoundDrawables(left, top, right, bottom); 66 | } 67 | 68 | @Override 69 | public boolean onTouchEvent(MotionEvent event) { 70 | Rect bounds; 71 | if (event.getAction() == MotionEvent.ACTION_DOWN) { 72 | actionX = (int) event.getX(); 73 | actionY = (int) event.getY(); 74 | if (drawableBottom != null 75 | && drawableBottom.getBounds().contains(actionX, actionY)) { 76 | clickListener.onClick(DrawableClickListener.DrawablePosition.BOTTOM); 77 | return super.onTouchEvent(event); 78 | } 79 | 80 | if (drawableTop != null 81 | && drawableTop.getBounds().contains(actionX, actionY)) { 82 | clickListener.onClick(DrawableClickListener.DrawablePosition.TOP); 83 | return super.onTouchEvent(event); 84 | } 85 | 86 | // this works for left since container shares 0,0 origin with bounds 87 | if (drawableLeft != null) { 88 | bounds = drawableLeft.getBounds(); 89 | 90 | int x, y; 91 | float density = getResources().getDisplayMetrics().density; 92 | int extraTapArea = (int) (13 * density + 0.5); 93 | 94 | x = actionX; 95 | y = actionY; 96 | 97 | if (!bounds.contains(actionX, actionY)) { 98 | /** Gives the +20 area for tapping. */ 99 | x = (int) (actionX - extraTapArea); 100 | y = (int) (actionY - extraTapArea); 101 | 102 | if (x <= 0) { 103 | x = actionX; 104 | } 105 | if (y <= 0) { 106 | y = actionY; 107 | } 108 | 109 | /** Creates square from the smallest value */ 110 | if (x < y) { 111 | y = x; 112 | } 113 | } 114 | 115 | if (bounds.contains(x, y) && clickListener != null) { 116 | clickListener 117 | .onClick(DrawableClickListener.DrawablePosition.LEFT); 118 | event.setAction(MotionEvent.ACTION_CANCEL); 119 | return false; 120 | 121 | } 122 | } 123 | 124 | if (drawableRight != null) { 125 | 126 | bounds = null; 127 | bounds = drawableRight.getBounds(); 128 | 129 | int x, y; 130 | int extraTapArea = 13; 131 | 132 | /** 133 | * IF USER CLICKS JUST OUT SIDE THE RECTANGLE OF THE DRAWABLE 134 | * THAN ADD X AND SUBTRACT THE Y WITH SOME VALUE SO THAT AFTER 135 | * CALCULATING X AND Y CO-ORDINATE LIES INTO THE DRAWBABLE 136 | * BOUND. - this process help to increase the tappable area of 137 | * the rectangle. 138 | */ 139 | x = (int) (actionX + extraTapArea); 140 | y = (int) (actionY - extraTapArea); 141 | 142 | /**Since this is right drawable subtract the value of x from the width 143 | * of view. so that width - tappedarea will result in x co-ordinate in drawable bound. 144 | */ 145 | x = getWidth() - x; 146 | 147 | /*x can be negative if user taps at x co-ordinate just near the width. 148 | * e.g views width = 300 and user taps 290. Then as per previous calculation 149 | * 290 + 13 = 303. So subtract X from getWidth() will result in negative value. 150 | * So to avoid this add the value previous added when x goes negative. 151 | */ 152 | 153 | if (x <= 0) { 154 | x += extraTapArea; 155 | } 156 | 157 | /* If result after calculating for extra tappable area is negative. 158 | * assign the original value so that after subtracting 159 | * extratapping area value doesn't go into negative value. 160 | */ 161 | 162 | if (y <= 0) { 163 | y = actionY; 164 | } 165 | 166 | /**If drawble bounds contains the x and y points then move ahead.*/ 167 | if (bounds.contains(x, y) && clickListener != null) { 168 | clickListener 169 | .onClick(DrawableClickListener.DrawablePosition.RIGHT); 170 | event.setAction(MotionEvent.ACTION_CANCEL); 171 | return false; 172 | } 173 | return super.onTouchEvent(event); 174 | } 175 | 176 | } 177 | return super.onTouchEvent(event); 178 | } 179 | 180 | public void addClearButton() { 181 | mClearButton = getResources().getDrawable(android.R.drawable.ic_menu_close_clear_cancel); 182 | setCompoundDrawablesWithIntrinsicBounds(null, null, TextUtils 183 | .isEmpty(getText().toString()) ? null : mClearButton, null); 184 | setDrawableClickListener(new DrawableClickListener() { 185 | @Override 186 | public void onClick(DrawablePosition target) { 187 | switch (target) { 188 | case TOP: 189 | break; 190 | case BOTTOM: 191 | break; 192 | case LEFT: 193 | break; 194 | case RIGHT: 195 | setText(""); 196 | break; 197 | } 198 | } 199 | }); 200 | addTextChangedListener(new TextWatcher() { 201 | @Override 202 | public void beforeTextChanged(CharSequence s, int start, int count, int after) { 203 | 204 | } 205 | 206 | @Override 207 | public void onTextChanged(CharSequence s, int start, int before, int count) { 208 | setCompoundDrawablesWithIntrinsicBounds(null, null, 209 | TextUtils.isEmpty(getText().toString()) ? null : mClearButton, null); 210 | } 211 | 212 | @Override 213 | public void afterTextChanged(Editable s) { 214 | 215 | } 216 | }); 217 | } 218 | 219 | 220 | @Override 221 | protected void finalize() throws Throwable { 222 | drawableRight = null; 223 | drawableBottom = null; 224 | drawableLeft = null; 225 | drawableTop = null; 226 | mClearButton = null; 227 | super.finalize(); 228 | } 229 | 230 | public void setDrawableClickListener(DrawableClickListener listener) { 231 | this.clickListener = listener; 232 | } 233 | 234 | } -------------------------------------------------------------------------------- /ACalDAV/src/org/gege/caldavsyncadapter/CalendarColors.java: -------------------------------------------------------------------------------- 1 | package org.gege.caldavsyncadapter; 2 | 3 | public class CalendarColors { 4 | 5 | // Colors come from Solarized, (c) ETHAN SCHOONOVER 6 | // http://ethanschoonover.com/solarized 7 | 8 | // SOLARIZED HEX 16/8 TERMCOL XTERM/HEX L*A*B RGB HSB 9 | // --------- ------- ---- ------- ----------- ---------- ----------- ----------- 10 | // base03 #002b36 8/4 brblack 234 #1c1c1c 15 -12 -12 0 43 54 193 100 21 11 | // base02 #073642 0/4 black 235 #262626 20 -12 -12 7 54 66 192 90 26 12 | // base01 #586e75 10/7 brgreen 240 #585858 45 -07 -07 88 110 117 194 25 46 13 | // base00 #657b83 11/7 bryellow 241 #626262 50 -07 -07 101 123 131 195 23 51 14 | // base0 #839496 12/6 brblue 244 #808080 60 -06 -03 131 148 150 186 13 59 15 | // base1 #93a1a1 14/4 brcyan 245 #8a8a8a 65 -05 -02 147 161 161 180 9 63 16 | // base2 #eee8d5 7/7 white 254 #e4e4e4 92 -00 10 238 232 213 44 11 93 17 | // base3 #fdf6e3 15/7 brwhite 230 #ffffd7 97 00 10 253 246 227 44 10 99 18 | // yellow #b58900 3/3 yellow 136 #af8700 60 10 65 181 137 0 45 100 71 19 | // orange #cb4b16 9/3 brred 166 #d75f00 50 50 55 203 75 22 18 89 80 20 | // red #dc322f 1/1 red 160 #d70000 50 65 45 220 50 47 1 79 86 21 | // magenta #d33682 5/5 magenta 125 #af005f 50 65 -05 211 54 130 331 74 83 22 | // violet #6c71c4 13/5 brmagenta 61 #5f5faf 50 15 -45 108 113 196 237 45 77 23 | // blue #268bd2 4/4 blue 33 #0087ff 55 -10 -45 38 139 210 205 82 82 24 | // cyan #2aa198 6/6 cyan 37 #00afaf 60 -35 -05 42 161 152 175 74 63 25 | // green #859900 2/2 green 64 #5f8700 60 -20 65 133 153 0 68 100 60 26 | 27 | public static long colors[] = { 28 | 0xffb58900, // yellow 29 | 0xffcb4b16, // orange 30 | 0xffdc322f, // red 31 | 0xffd33682, // magenta 32 | 0xff6c71c4, // violet 33 | 0xff268bd2, // blue 34 | 0xff2aa198, // cyan 35 | 0xff859900 // green 36 | }; 37 | 38 | } 39 | -------------------------------------------------------------------------------- /ACalDAV/src/org/gege/caldavsyncadapter/Constants.java: -------------------------------------------------------------------------------- 1 | package org.gege.caldavsyncadapter; 2 | 3 | /** 4 | * @author Joseph Weigl 5 | */ 6 | public interface Constants { 7 | 8 | String USER_DATA_TRUST_ALL_KEY = "USER_DATA_TRUSTALL_KEY"; 9 | String INVALID_CREDENTIALS_CHECK="CREDENTIALS_CHECK";} -------------------------------------------------------------------------------- /ACalDAV/src/org/gege/caldavsyncadapter/Event.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Gerald Garcia, Timo Berger 3 | * 4 | * This file is part of Andoid Caldav Sync Adapter Free. 5 | * 6 | * Andoid Caldav Sync Adapter Free is free software: you can redistribute 7 | * it and/or modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation, either version 3 of the 9 | * License, or at your option any later version. 10 | * 11 | * Andoid Caldav Sync Adapter Free is distributed in the hope that 12 | * it will be useful, but WITHOUT ANY WARRANTY; without even the implied 13 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with Andoid Caldav Sync Adapter Free. 18 | * If not, see . 19 | * 20 | */ 21 | package org.gege.caldavsyncadapter; 22 | 23 | import android.content.ContentValues; 24 | import android.provider.CalendarContract.Events; 25 | import android.util.Log; 26 | 27 | import java.util.ArrayList; 28 | 29 | /** 30 | * abstract class for Calendar and Android events 31 | */ 32 | abstract public class Event { 33 | 34 | /** 35 | * stores the ETAG of an event 36 | */ 37 | public final static String ETAG = Events.SYNC_DATA1; 38 | 39 | private static final String TAG = "Event"; 40 | 41 | /** 42 | * internal Tag used to identify deleted events 43 | */ 44 | public static String INTERNALTAG = Events.SYNC_DATA2; 45 | 46 | /** 47 | * store the whole VEVENT in here 48 | * missing TAGs they might be missing for google update 49 | * 50 | * CREATED:20130906T102857Z 51 | * DTSTAMP:20130906T102857Z 52 | * LAST-MODIFIED:20130906T102857Z 53 | * SEQUENCE:0 54 | */ 55 | public static String RAWDATA = Events.SYNC_DATA3; 56 | 57 | /** 58 | * stores the UID of an Event 59 | * example: UID:e6be67c6-eff0-44f8-a1a0-6c2cb1029944-caldavsyncadapter 60 | */ 61 | public static String UID = Events.SYNC_DATA4; 62 | 63 | /** 64 | * the event transformed into ContentValues 65 | */ 66 | public ContentValues ContentValues = new ContentValues(); 67 | 68 | /** 69 | * returns a list of all items that are comparable with this sync adapter 70 | * 71 | * @return a list of all items that are comparable with this sync adapter 72 | */ 73 | public static java.util.ArrayList getComparableItems() { 74 | ArrayList lcResult = new ArrayList(); 75 | lcResult.add(Events.DTSTART); 76 | lcResult.add(Events.DTEND); 77 | lcResult.add(Events.EVENT_TIMEZONE); 78 | lcResult.add(Events.EVENT_END_TIMEZONE); 79 | lcResult.add(Events.ALL_DAY); 80 | lcResult.add(Events.DURATION); 81 | lcResult.add(Events.TITLE); 82 | lcResult.add(Events.CALENDAR_ID); 83 | lcResult.add(Events._SYNC_ID); 84 | lcResult.add(ETAG); 85 | lcResult.add(Events.DESCRIPTION); 86 | lcResult.add(Events.EVENT_LOCATION); 87 | lcResult.add(Events.ACCESS_LEVEL); 88 | lcResult.add(Events.STATUS); 89 | lcResult.add(Events.RDATE); 90 | lcResult.add(Events.RRULE); 91 | lcResult.add(Events.EXRULE); 92 | lcResult.add(Events.EXDATE); 93 | lcResult.add(UID); 94 | 95 | return lcResult; 96 | } 97 | 98 | abstract public String getETag(); 99 | 100 | abstract public void setETag(String ETag); 101 | 102 | /** 103 | * returns the AndroidCalendarId for this event. 104 | * 105 | * @return the AndroidCalendarId for this event 106 | */ 107 | public long getAndroidCalendarId() { 108 | long lcResult = -1; 109 | if (this.ContentValues.containsKey(Events.CALENDAR_ID)) { 110 | lcResult = this.ContentValues.getAsLong(Events.CALENDAR_ID); 111 | } 112 | return lcResult; 113 | } 114 | 115 | /** 116 | * sets the AndroidCalendarId for this event 117 | * 118 | * @param ID the AndroidCalendarId for this event 119 | */ 120 | public void setAndroidCalendarId(long ID) { 121 | if (this.ContentValues.containsKey(Events.CALENDAR_ID)) { 122 | this.ContentValues.remove(Events.CALENDAR_ID); 123 | } 124 | 125 | this.ContentValues.put(Events.CALENDAR_ID, ID); 126 | } 127 | 128 | /** 129 | * returns the UID for this event. you can also check, whether the UID was stored from server. 130 | * the V1.7 release and before didn't save them. 131 | * example: UID:e6be67c6-eff0-44f8-a1a0-6c2cb1029944-caldavsyncadapter 132 | * 133 | * @return the UID for this event 134 | */ 135 | public String getUID() { 136 | String lcResult = ""; 137 | if (this.ContentValues.containsKey(UID)) { 138 | lcResult = this.ContentValues.getAsString(UID); 139 | } 140 | 141 | return lcResult; 142 | } 143 | 144 | /** 145 | * compares the given ContentValues with the current ones for differences 146 | * 147 | * @param calendarEventValues the contentValues of the calendar event 148 | * @return if the events are different 149 | */ 150 | public boolean checkEventValuesChanged(ContentValues calendarEventValues) { 151 | boolean lcResult = false; 152 | Object lcValueAndroid = null; 153 | Object lcValueCalendar = null; 154 | java.util.ArrayList lcCompareItems = Event.getComparableItems(); 155 | 156 | for (String key : lcCompareItems) { 157 | 158 | if (this.ContentValues.containsKey(key)) { 159 | lcValueAndroid = this.ContentValues.get(key); 160 | } else { 161 | lcValueAndroid = null; 162 | } 163 | 164 | if (calendarEventValues.containsKey(key)) { 165 | lcValueCalendar = calendarEventValues.get(key); 166 | } else { 167 | lcValueCalendar = null; 168 | } 169 | 170 | /* 171 | * TODO: Sync is designed to "Server always wins", should be a general option for this adapter 172 | */ 173 | if (lcValueAndroid != null) { 174 | if (lcValueCalendar != null) { 175 | if (!lcValueAndroid.toString().equals(lcValueCalendar.toString())) { 176 | Log.d(TAG, "difference in " + key.toString() + ":" + lcValueAndroid.toString() 177 | + " <> " + lcValueCalendar.toString()); 178 | this.ContentValues.put(key, lcValueCalendar.toString()); 179 | lcResult = true; 180 | } 181 | } else { 182 | Log.d(TAG, "difference in " + key.toString() + ":" + lcValueAndroid.toString() 183 | + " <> null"); 184 | this.ContentValues.putNull(key); 185 | lcResult = true; 186 | } 187 | } else { 188 | if (lcValueCalendar != null) { 189 | Log.d(TAG, "difference in " + key.toString() + ":null <> " + lcValueCalendar 190 | .toString()); 191 | this.ContentValues.put(key, lcValueCalendar.toString()); 192 | lcResult = true; 193 | } else { 194 | // both null -> this is ok 195 | } 196 | } 197 | } 198 | 199 | return lcResult; 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /ACalDAV/src/org/gege/caldavsyncadapter/android/entities/AndroidEvent.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Gerald Garcia, Timo Berger 3 | * 4 | * This file is part of Andoid Caldav Sync Adapter Free. 5 | * 6 | * Andoid Caldav Sync Adapter Free is free software: you can redistribute 7 | * it and/or modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation, either version 3 of the 9 | * License, or at your option any later version. 10 | * 11 | * Andoid Caldav Sync Adapter Free is distributed in the hope that 12 | * it will be useful, but WITHOUT ANY WARRANTY; without even the implied 13 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with Andoid Caldav Sync Adapter Free. 18 | * If not, see . 19 | */ 20 | 21 | 22 | package org.gege.caldavsyncadapter.android.entities; 23 | 24 | import android.database.Cursor; 25 | import android.net.Uri; 26 | import android.provider.CalendarContract.Attendees; 27 | import android.provider.CalendarContract.Events; 28 | import android.provider.CalendarContract.Reminders; 29 | import android.util.Log; 30 | 31 | import net.fortuna.ical4j.model.Calendar; 32 | import net.fortuna.ical4j.model.Component; 33 | import net.fortuna.ical4j.model.ComponentList; 34 | import net.fortuna.ical4j.model.Date; 35 | import net.fortuna.ical4j.model.DateTime; 36 | import net.fortuna.ical4j.model.Dur; 37 | import net.fortuna.ical4j.model.ParameterList; 38 | import net.fortuna.ical4j.model.Property; 39 | import net.fortuna.ical4j.model.PropertyList; 40 | import net.fortuna.ical4j.model.TimeZone; 41 | import net.fortuna.ical4j.model.TimeZoneRegistry; 42 | import net.fortuna.ical4j.model.TimeZoneRegistryFactory; 43 | import net.fortuna.ical4j.model.component.VAlarm; 44 | import net.fortuna.ical4j.model.component.VEvent; 45 | import net.fortuna.ical4j.model.parameter.Cn; 46 | import net.fortuna.ical4j.model.parameter.PartStat; 47 | import net.fortuna.ical4j.model.parameter.Role; 48 | import net.fortuna.ical4j.model.parameter.Rsvp; 49 | import net.fortuna.ical4j.model.parameter.Value; 50 | import net.fortuna.ical4j.model.property.Action; 51 | import net.fortuna.ical4j.model.property.Attendee; 52 | import net.fortuna.ical4j.model.property.CalScale; 53 | import net.fortuna.ical4j.model.property.Clazz; 54 | import net.fortuna.ical4j.model.property.Description; 55 | import net.fortuna.ical4j.model.property.DtEnd; 56 | import net.fortuna.ical4j.model.property.DtStart; 57 | import net.fortuna.ical4j.model.property.Duration; 58 | import net.fortuna.ical4j.model.property.ExDate; 59 | import net.fortuna.ical4j.model.property.ExRule; 60 | import net.fortuna.ical4j.model.property.Location; 61 | import net.fortuna.ical4j.model.property.Organizer; 62 | import net.fortuna.ical4j.model.property.ProdId; 63 | import net.fortuna.ical4j.model.property.RDate; 64 | import net.fortuna.ical4j.model.property.RRule; 65 | import net.fortuna.ical4j.model.property.Status; 66 | import net.fortuna.ical4j.model.property.Summary; 67 | import net.fortuna.ical4j.model.property.Trigger; 68 | import net.fortuna.ical4j.model.property.Uid; 69 | import net.fortuna.ical4j.model.property.Version; 70 | 71 | import org.gege.caldavsyncadapter.caldav.entities.CalendarEvent; 72 | 73 | import java.net.URISyntaxException; 74 | import java.text.ParseException; 75 | 76 | import de.we.acaldav.App; 77 | 78 | //import android.accounts.Account; 79 | //import android.content.ContentProviderClient; 80 | //import android.content.ContentValues; 81 | //import android.content.SyncStats; 82 | //import android.os.RemoteException; 83 | //import android.provider.CalendarContract.Calendars; 84 | //import org.gege.caldavsyncadapter.Event; 85 | //import org.gege.caldavsyncadapter.caldav.CaldavFacade; 86 | //import org.gege.caldavsyncadapter.caldav.entities.DavCalendar; 87 | //import org.gege.caldavsyncadapter.syncadapter.SyncAdapter; 88 | 89 | public class AndroidEvent extends org.gege.caldavsyncadapter.Event { 90 | 91 | private Uri muri; 92 | 93 | private Uri mAndroidCalendarUri; 94 | 95 | /** 96 | * the list of attendees 97 | */ 98 | private PropertyList mAttendees = new PropertyList(); 99 | 100 | /** 101 | * the list of reminders 102 | */ 103 | private ComponentList mReminders = new ComponentList(); 104 | 105 | private Calendar mCalendar = null; 106 | 107 | public AndroidEvent(Uri uri, Uri calendarUri) { 108 | super(); 109 | this.setUri(uri); 110 | mAndroidCalendarUri = calendarUri; 111 | } 112 | 113 | public Calendar getIcsEvent() { 114 | return mCalendar; 115 | } 116 | 117 | public String getETag() { 118 | String result = ""; 119 | if (this.ContentValues.containsKey(ETAG)) { 120 | result = this.ContentValues.getAsString(ETAG); 121 | } 122 | return result; 123 | } 124 | 125 | public void setETag(String eTag) { 126 | this.ContentValues.put(ETAG, eTag); 127 | } 128 | 129 | public Uri getUri() { 130 | return muri; 131 | } 132 | 133 | public void setUri(Uri uri) { 134 | this.muri = uri; 135 | } 136 | 137 | public Uri getAndroidCalendarUri() { 138 | return mAndroidCalendarUri; 139 | } 140 | 141 | @Override 142 | public String toString() { 143 | return this.getUri().toString(); 144 | } 145 | 146 | /** 147 | * reads an android event from a given cursor into {@link AndroidEvent#ContentValues} 148 | * 149 | * @param cur the cursor with the event 150 | * @return success of this funtion 151 | * @see AndroidEvent#ContentValues 152 | */ 153 | public boolean readContentValues(Cursor cur) { 154 | this.setETag(cur.getString(cur.getColumnIndex(ETAG))); 155 | 156 | this.ContentValues.put(Events._ID, cur.getString(cur.getColumnIndex(Events._ID))); 157 | this.ContentValues.put(Events.ORIGINAL_ID, cur.getString(cur.getColumnIndex(Events.ORIGINAL_ID))); 158 | this.ContentValues.put(Events.ORIGINAL_SYNC_ID, cur.getString(cur.getColumnIndex(Events.ORIGINAL_SYNC_ID))); 159 | this.ContentValues.put(Events.EVENT_TIMEZONE, 160 | cur.getString(cur.getColumnIndex(Events.EVENT_TIMEZONE))); 161 | this.ContentValues.put(Events.EVENT_END_TIMEZONE, 162 | cur.getString(cur.getColumnIndex(Events.EVENT_END_TIMEZONE))); 163 | this.ContentValues.put(Events.DTSTART, cur.getLong(cur.getColumnIndex(Events.DTSTART))); 164 | this.ContentValues.put(Events.DTEND, cur.getLong(cur.getColumnIndex(Events.DTEND))); 165 | this.ContentValues.put(Events.ALL_DAY, cur.getLong(cur.getColumnIndex(Events.ALL_DAY))); 166 | this.ContentValues.put(Events.TITLE, cur.getString(cur.getColumnIndex(Events.TITLE))); 167 | this.ContentValues 168 | .put(Events.CALENDAR_ID, cur.getString(cur.getColumnIndex(Events.CALENDAR_ID))); 169 | this.ContentValues.put(Events._SYNC_ID, cur.getString(cur.getColumnIndex(Events._SYNC_ID))); 170 | this.ContentValues 171 | .put(Events.DESCRIPTION, cur.getString(cur.getColumnIndex(Events.DESCRIPTION))); 172 | this.ContentValues.put(Events.EVENT_LOCATION, 173 | cur.getString(cur.getColumnIndex(Events.EVENT_LOCATION))); 174 | this.ContentValues 175 | .put(Events.ACCESS_LEVEL, cur.getInt(cur.getColumnIndex(Events.ACCESS_LEVEL))); 176 | 177 | this.ContentValues.put(Events.STATUS, cur.getInt(cur.getColumnIndex(Events.STATUS))); 178 | 179 | this.ContentValues.put(Events.LAST_DATE, cur.getInt(cur.getColumnIndex(Events.LAST_DATE))); 180 | this.ContentValues.put(Events.DURATION, cur.getString(cur.getColumnIndex(Events.DURATION))); 181 | 182 | this.ContentValues.put(Events.RDATE, cur.getString(cur.getColumnIndex(Events.RDATE))); 183 | this.ContentValues.put(Events.RRULE, cur.getString(cur.getColumnIndex(Events.RRULE))); 184 | this.ContentValues.put(Events.EXRULE, cur.getString(cur.getColumnIndex(Events.EXRULE))); 185 | this.ContentValues.put(Events.EXDATE, cur.getString(cur.getColumnIndex(Events.EXDATE))); 186 | this.ContentValues.put(Events.DIRTY, cur.getInt(cur.getColumnIndex(Events.DIRTY))); 187 | this.ContentValues.put(UID, cur.getString(cur.getColumnIndex(UID))); 188 | this.ContentValues.put(RAWDATA, cur.getString(cur.getColumnIndex(RAWDATA))); 189 | 190 | return true; 191 | } 192 | 193 | /** 194 | * reads the attendees from a given cursor 195 | * 196 | * @param cur the cursor with the attendees 197 | * @return success of this function 198 | * @see AndroidEvent#mAttendees 199 | */ 200 | public boolean readAttendees(Cursor cur) { 201 | Attendee attendee = null; 202 | Organizer organizer = null; 203 | ParameterList paraList = null; 204 | 205 | String name = ""; 206 | Cn cn = null; 207 | 208 | String email = ""; 209 | 210 | int relationship = 0; 211 | 212 | int status = 0; 213 | PartStat partstat = null; 214 | 215 | int type = 0; 216 | Role role = null; 217 | 218 | try { 219 | while (cur.moveToNext()) { 220 | name = cur.getString(cur.getColumnIndex(Attendees.ATTENDEE_NAME)); 221 | email = cur.getString(cur.getColumnIndex(Attendees.ATTENDEE_EMAIL)); 222 | relationship = cur.getInt(cur.getColumnIndex(Attendees.ATTENDEE_RELATIONSHIP)); 223 | type = cur.getInt(cur.getColumnIndex(Attendees.ATTENDEE_TYPE)); 224 | status = cur.getInt(cur.getColumnIndex(Attendees.ATTENDEE_STATUS)); 225 | 226 | if (relationship == Attendees.RELATIONSHIP_ORGANIZER) { 227 | organizer = new Organizer(); 228 | organizer.setValue("mailto:" + email); 229 | paraList = organizer.getParameters(); 230 | mAttendees.add(organizer); 231 | } else { 232 | attendee = new Attendee(); 233 | attendee.setValue("mailto:" + email); 234 | paraList = attendee.getParameters(); 235 | mAttendees.add(attendee); 236 | } 237 | 238 | Rsvp rsvp = new Rsvp(true); 239 | paraList.add(rsvp); 240 | 241 | cn = new Cn(name); 242 | paraList.add(cn); 243 | 244 | if (status == Attendees.ATTENDEE_STATUS_INVITED) { 245 | partstat = new PartStat(PartStat.NEEDS_ACTION.getValue()); 246 | } else if (status == Attendees.ATTENDEE_STATUS_ACCEPTED) { 247 | partstat = new PartStat(PartStat.ACCEPTED.getValue()); 248 | } else if (status == Attendees.ATTENDEE_STATUS_DECLINED) { 249 | partstat = new PartStat(PartStat.DECLINED.getValue()); 250 | } else if (status == Attendees.ATTENDEE_STATUS_NONE) { 251 | partstat = new PartStat(PartStat.COMPLETED.getValue()); 252 | } else if (status == Attendees.ATTENDEE_STATUS_TENTATIVE) { 253 | partstat = new PartStat(PartStat.TENTATIVE.getValue()); 254 | } else { 255 | partstat = new PartStat(PartStat.NEEDS_ACTION.getValue()); 256 | } 257 | paraList.add(partstat); 258 | 259 | if (type == Attendees.TYPE_OPTIONAL) { 260 | role = new Role(Role.OPT_PARTICIPANT.getValue()); 261 | } else if (type == Attendees.TYPE_NONE) { 262 | role = new Role(Role.NON_PARTICIPANT 263 | .getValue()); //regular participants in android are non required? 264 | } else if (type == Attendees.TYPE_REQUIRED) { 265 | role = new Role(Role.REQ_PARTICIPANT.getValue()); 266 | } else { 267 | role = new Role(Role.NON_PARTICIPANT.getValue()); 268 | } 269 | paraList.add(role); 270 | } 271 | 272 | } catch (URISyntaxException e) { 273 | Log.e(getETag(), e.getMessage()); 274 | } 275 | return true; 276 | } 277 | 278 | /** 279 | * reads the reminders from a given cursor 280 | * 281 | * @param cur the cursor with the reminders 282 | * @return success of this function 283 | */ 284 | public boolean readReminder(Cursor cur) { 285 | int method; 286 | int minutes; 287 | VAlarm reminder; 288 | while (cur.moveToNext()) { 289 | reminder = new VAlarm(); 290 | method = cur.getInt(cur.getColumnIndex(Reminders.METHOD)); 291 | minutes = cur.getInt(cur.getColumnIndex(Reminders.MINUTES)) * -1; 292 | 293 | Dur dur = new Dur(0, 0, minutes, 0); 294 | Trigger tri = new Trigger(dur); 295 | Value val = new Value(Duration.DURATION); 296 | tri.getParameters().add(val); 297 | reminder.getProperties().add(tri); 298 | 299 | Description desc = new Description(); 300 | desc.setValue("caldavsyncadapter standard description"); 301 | reminder.getProperties().add(desc); 302 | 303 | if (method == Reminders.METHOD_EMAIL) { 304 | reminder.getProperties().add(Action.EMAIL); 305 | } else { 306 | reminder.getProperties().add(Action.DISPLAY); 307 | } 308 | 309 | this.mReminders.add(reminder); 310 | } 311 | return true; 312 | } 313 | 314 | /** 315 | * generates a new ics-file. 316 | * uses {@link AndroidEvent#ContentValues} as source. 317 | * this should only be used when a new event has been generated within android. 318 | * 319 | * @param strUid the UID for this event. example: UID:e6be67c6-eff0-44f8-a1a0-6c2cb1029944-caldavsyncadapter 320 | * @return success of the function 321 | * @see CalendarEvent#fetchBody() 322 | */ 323 | public boolean createIcs(String strUid) { 324 | boolean result = false; 325 | TimeZone timeZone = null; 326 | Thread.currentThread().setContextClassLoader(App.getContext().getClassLoader()); 327 | TimeZoneRegistry registry = TimeZoneRegistryFactory.getInstance().createRegistry(); 328 | 329 | //TODO: do not simply create the ics-file new. take into account the RAWDATA if available 330 | 331 | try { 332 | mCalendar = new Calendar(); 333 | PropertyList propCalendar = mCalendar.getProperties(); 334 | propCalendar.add(new ProdId("-//Ben Fortuna//iCal4j 1.0//EN")); 335 | propCalendar.add(Version.VERSION_2_0); 336 | propCalendar.add(CalScale.GREGORIAN); 337 | 338 | VEvent event = new VEvent(); 339 | mCalendar.getComponents().add(event); 340 | PropertyList propEvent = event.getProperties(); 341 | 342 | // DTSTART 343 | long lngStart = this.ContentValues.getAsLong(Events.DTSTART); 344 | String strTZStart = this.ContentValues.getAsString(Events.EVENT_TIMEZONE); 345 | boolean allDay = this.ContentValues.getAsBoolean(Events.ALL_DAY); 346 | if (lngStart > 0) { 347 | DtStart dtStart = new DtStart(); 348 | if (allDay) { 349 | Date dateStart = new Date(); 350 | dateStart.setTime(lngStart); 351 | dtStart.setDate(dateStart); 352 | } else { 353 | DateTime datetimeStart = new DateTime(); 354 | datetimeStart.setTime(lngStart); 355 | dtStart.setDate(datetimeStart); 356 | 357 | timeZone = registry.getTimeZone(strTZStart); 358 | if (timeZone == null) { 359 | java.util.TimeZone systemTimeZone = TimeZone.getTimeZone(strTZStart); 360 | if (systemTimeZone == null) { 361 | systemTimeZone = TimeZone.getDefault(); 362 | } 363 | timeZone = registry.getTimeZone(systemTimeZone.getID()); 364 | } 365 | dtStart.setTimeZone(timeZone); 366 | 367 | // no timezone information for allDay events 368 | mCalendar.getComponents().add(timeZone.getVTimeZone()); 369 | } 370 | propEvent.add(dtStart); 371 | } 372 | 373 | // DTEND 374 | long lngEnd = this.ContentValues.getAsLong(Events.DTEND); 375 | String strTZEnd = this.ContentValues.getAsString(Events.EVENT_END_TIMEZONE); 376 | if (strTZEnd == null) { 377 | strTZEnd = strTZStart; 378 | } 379 | if (lngEnd > 0) { 380 | DtEnd dtEnd = new DtEnd(); 381 | if (allDay) { 382 | Date dateEnd = new Date(); 383 | dateEnd.setTime(lngEnd); 384 | dtEnd.setDate(dateEnd); 385 | } else { 386 | DateTime datetimeEnd = new DateTime(); 387 | datetimeEnd.setTime(lngEnd); 388 | dtEnd.setDate(datetimeEnd); 389 | if (strTZEnd != null) { 390 | timeZone = registry.getTimeZone(strTZEnd); 391 | } 392 | dtEnd.setTimeZone(timeZone); 393 | } 394 | propEvent.add(dtEnd); 395 | } 396 | 397 | // DURATION 398 | if (this.ContentValues.containsKey(Events.DURATION)) { 399 | String strDuration = this.ContentValues.getAsString(Events.DURATION); 400 | if (strDuration != null) { 401 | Duration duration = new Duration(); 402 | duration.setValue(strDuration); 403 | 404 | propEvent.add(duration); 405 | } 406 | } 407 | 408 | //RRULE 409 | if (this.ContentValues.containsKey(Events.RRULE)) { 410 | String strRrule = this.ContentValues.getAsString(Events.RRULE); 411 | if (strRrule != null) { 412 | if (!strRrule.equals("")) { 413 | RRule rrule = new RRule(); 414 | rrule.setValue(strRrule); 415 | propEvent.add(rrule); 416 | } 417 | } 418 | } 419 | 420 | //RDATE 421 | if (this.ContentValues.containsKey(Events.RDATE)) { 422 | String strRdate = this.ContentValues.getAsString(Events.RDATE); 423 | if (strRdate != null) { 424 | if (!strRdate.equals("")) { 425 | RDate rdate = new RDate(); 426 | rdate.setValue(strRdate); 427 | propEvent.add(rdate); 428 | } 429 | } 430 | } 431 | 432 | //EXRULE 433 | if (this.ContentValues.containsKey(Events.EXRULE)) { 434 | String strExrule = this.ContentValues.getAsString(Events.EXRULE); 435 | if (strExrule != null) { 436 | if (!strExrule.equals("")) { 437 | ExRule exrule = new ExRule(); 438 | exrule.setValue(strExrule); 439 | propEvent.add(exrule); 440 | } 441 | } 442 | } 443 | 444 | //EXDATE 445 | if (this.ContentValues.containsKey(Events.EXDATE)) { 446 | String strExdate = this.ContentValues.getAsString(Events.EXDATE); 447 | if (strExdate != null) { 448 | if (!strExdate.equals("")) { 449 | ExDate exdate = new ExDate(); 450 | exdate.setValue(strExdate); 451 | propEvent.add(exdate); 452 | } 453 | } 454 | } 455 | 456 | //SUMMARY 457 | if (this.ContentValues.containsKey(Events.TITLE)) { 458 | String strTitle = this.ContentValues.getAsString(Events.TITLE); 459 | if (strTitle != null) { 460 | Summary summary = new Summary(strTitle); 461 | propEvent.add(summary); 462 | } 463 | } 464 | 465 | //DESCIPTION 466 | if (this.ContentValues.containsKey(Events.DESCRIPTION)) { 467 | String strDescription = this.ContentValues.getAsString(Events.DESCRIPTION); 468 | if (strDescription != null) { 469 | if (!strDescription.equals("")) { 470 | Description description = new Description(strDescription); 471 | propEvent.add(description); 472 | } 473 | } 474 | } 475 | 476 | //LOCATION 477 | if (this.ContentValues.containsKey(Events.EVENT_LOCATION)) { 478 | String strLocation = this.ContentValues.getAsString(Events.EVENT_LOCATION); 479 | if (strLocation != null) { 480 | if (!strLocation.equals("")) { 481 | Location location = new Location(strLocation); 482 | propEvent.add(location); 483 | } 484 | } 485 | } 486 | 487 | //CLASS / ACCESS_LEVEL 488 | if (this.ContentValues.containsKey(Events.ACCESS_LEVEL)) { 489 | int accessLevel = this.ContentValues.getAsInteger(Events.ACCESS_LEVEL); 490 | Clazz clazz = new Clazz(); 491 | if (accessLevel == Events.ACCESS_PUBLIC) { 492 | clazz.setValue(Clazz.PUBLIC.getValue()); 493 | } else if (accessLevel == Events.ACCESS_PRIVATE) { 494 | clazz.setValue(Clazz.PRIVATE.getValue()); 495 | } else if (accessLevel == Events.ACCESS_CONFIDENTIAL) { 496 | clazz.setValue(Clazz.CONFIDENTIAL.getValue()); 497 | } else { 498 | clazz.setValue(Clazz.PUBLIC.getValue()); 499 | } 500 | 501 | propEvent.add(clazz); 502 | } 503 | 504 | //STATUS 505 | if (this.ContentValues.containsKey(Events.STATUS)) { 506 | int intStatus = this.ContentValues.getAsInteger(Events.STATUS); 507 | if (intStatus > -1) { 508 | Status status = new Status(); 509 | if (intStatus == Events.STATUS_CANCELED) { 510 | status.setValue(Status.VEVENT_CANCELLED.getValue()); 511 | } else if (intStatus == Events.STATUS_CONFIRMED) { 512 | status.setValue(Status.VEVENT_CONFIRMED.getValue()); 513 | } else if (intStatus == Events.STATUS_TENTATIVE) { 514 | status.setValue(Status.VEVENT_TENTATIVE.getValue()); 515 | } 516 | 517 | propEvent.add(status); 518 | } 519 | } 520 | 521 | //UID 522 | Uid uid = new Uid(strUid); 523 | propEvent.add(uid); 524 | 525 | // Attendees 526 | if (mAttendees.size() > 0) { 527 | for (Object objProp : mAttendees) { 528 | Property prop = (Property) objProp; 529 | propEvent.add(prop); 530 | } 531 | } 532 | 533 | // Reminders 534 | if (mReminders.size() > 0) { 535 | for (Object objComp : mReminders) { 536 | Component com = (Component) objComp; 537 | event.getAlarms().add(com); 538 | } 539 | } 540 | 541 | } catch (ParseException e) { 542 | Log.e(getETag(), e.getMessage()); 543 | } 544 | 545 | return result; 546 | } 547 | } 548 | 549 | -------------------------------------------------------------------------------- /ACalDAV/src/org/gege/caldavsyncadapter/authenticator/AuthenticationService.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Gerald Garcia 3 | * 4 | * This file is part of Andoid Caldav Sync Adapter Free. 5 | * 6 | * Andoid Caldav Sync Adapter Free is free software: you can redistribute 7 | * it and/or modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation, either version 3 of the 9 | * License, or at your option any later version. 10 | * 11 | * Andoid Caldav Sync Adapter Free is distributed in the hope that 12 | * it will be useful, but WITHOUT ANY WARRANTY; without even the implied 13 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with Andoid Caldav Sync Adapter Free. 18 | * If not, see . 19 | * 20 | */ 21 | 22 | package org.gege.caldavsyncadapter.authenticator; 23 | 24 | import android.app.Service; 25 | import android.content.Intent; 26 | import android.os.IBinder; 27 | import android.util.Log; 28 | 29 | 30 | public class AuthenticationService extends Service { 31 | 32 | private static final String TAG = "AuthenticationService"; 33 | 34 | private AuthenticatorStub mAuthenticator; 35 | 36 | @Override 37 | public void onCreate() { 38 | if (Log.isLoggable(TAG, Log.VERBOSE)) { 39 | Log.v(TAG, "SampleSyncAdapter Authentication Service started."); 40 | } 41 | mAuthenticator = new AuthenticatorStub(this); 42 | } 43 | 44 | @Override 45 | public void onDestroy() { 46 | if (Log.isLoggable(TAG, Log.VERBOSE)) { 47 | Log.v(TAG, "SampleSyncAdapter Authentication Service stopped."); 48 | } 49 | } 50 | 51 | @Override 52 | public IBinder onBind(Intent intent) { 53 | if (Log.isLoggable(TAG, Log.VERBOSE)) { 54 | Log.v(TAG, "getBinder()... returning the AccountAuthenticator binder for intent " 55 | + intent); 56 | } 57 | return mAuthenticator.getIBinder(); 58 | } 59 | } -------------------------------------------------------------------------------- /ACalDAV/src/org/gege/caldavsyncadapter/authenticator/AuthenticatorActivity.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Gerald Garcia 3 | * 4 | * This file is part of Andoid Caldav Sync Adapter Free. 5 | * 6 | * Andoid Caldav Sync Adapter Free is free software: you can redistribute 7 | * it and/or modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation, either version 3 of the 9 | * License, or at your option any later version. 10 | * 11 | * Andoid Caldav Sync Adapter Free is distributed in the hope that 12 | * it will be useful, but WITHOUT ANY WARRANTY; without even the implied 13 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with Andoid Caldav Sync Adapter Free. 18 | * If not, see . 19 | */ 20 | 21 | package org.gege.caldavsyncadapter.authenticator; 22 | 23 | import android.accounts.Account; 24 | import android.accounts.AccountManager; 25 | import android.accounts.AccountManagerCallback; 26 | import android.accounts.AccountManagerFuture; 27 | import android.animation.Animator; 28 | import android.animation.AnimatorListenerAdapter; 29 | import android.annotation.TargetApi; 30 | import android.app.Activity; 31 | import android.app.NotificationManager; 32 | import android.content.ContentResolver; 33 | import android.content.Context; 34 | import android.content.Intent; 35 | import android.content.pm.PackageManager.NameNotFoundException; 36 | import android.graphics.drawable.Drawable; 37 | import android.os.AsyncTask; 38 | import android.os.Build; 39 | import android.os.Bundle; 40 | import android.os.PersistableBundle; 41 | import android.text.Editable; 42 | import android.text.TextUtils; 43 | import android.text.TextWatcher; 44 | import android.util.Log; 45 | import android.view.KeyEvent; 46 | import android.view.Menu; 47 | import android.view.View; 48 | import android.view.inputmethod.EditorInfo; 49 | import android.widget.CheckBox; 50 | import android.widget.EditText; 51 | import android.widget.TextView; 52 | import android.widget.Toast; 53 | 54 | import org.apache.commons.codec.binary.StringUtils; 55 | import org.apache.http.conn.HttpHostConnectException; 56 | import org.apache.http.conn.ssl.AbstractVerifier; 57 | import org.gege.caldavsyncadapter.Constants; 58 | import org.gege.caldavsyncadapter.caldav.CaldavFacade; 59 | import org.gege.caldavsyncadapter.caldav.CaldavFacade.TestConnectionResult; 60 | import org.xml.sax.SAXException; 61 | 62 | import java.io.IOException; 63 | import java.io.UnsupportedEncodingException; 64 | import java.net.MalformedURLException; 65 | import java.net.URISyntaxException; 66 | import java.util.Locale; 67 | import java.util.prefs.Preferences; 68 | 69 | import javax.xml.parsers.ParserConfigurationException; 70 | 71 | import de.we.acaldav.App; 72 | import de.we.acaldav.R; 73 | import de.we.acaldav.utilities.AccountUtility; 74 | import de.we.acaldav.widget.DrawableClickListener; 75 | import de.we.acaldav.widget.IconfiedEditText; 76 | 77 | /** 78 | * Activity which displays a login screen to the user, offering registration as 79 | * well. 80 | */ 81 | public class AuthenticatorActivity extends Activity { 82 | 83 | public static final String USER_DATA_URL_KEY = "USER_DATA_URL_KEY"; 84 | 85 | public static final String USER_DATA_USERNAME = "USER_DATA_USERNAME"; 86 | 87 | public static final String USER_DATA_UPDATE_INTERVAL = "USER_DATA_UPDATE_INTERVAL"; 88 | 89 | public static final String USER_DATA_VERSION = "USER_DATA_VERSION"; 90 | 91 | public static final String CURRENT_USER_DATA_VERSION = "1"; 92 | 93 | public static final String ACCOUNT_NAME_SPLITTER = "@"; 94 | 95 | private Account account; 96 | 97 | /** 98 | * The default email to populate the email field with. 99 | */ 100 | public static final String EXTRA_EMAIL = "com.example.android.authenticatordemo.extra.EMAIL"; 101 | 102 | private static final String TAG = "AuthenticatorActivity"; 103 | 104 | @Override 105 | public void onCreate(Bundle savedInstanceState, PersistableBundle persistentState) { 106 | super.onCreate(savedInstanceState, persistentState); 107 | } 108 | 109 | public static final String ACCOUNT_TYPE = "org.gege.caldavsyncadapter.account"; 110 | 111 | /** 112 | * Keep track of the login task to ensure we can cancel it if requested. 113 | */ 114 | private UserLoginTask mAuthTask = null; 115 | 116 | // Values for email and password at the time of the login attempt. 117 | private String mUser; 118 | 119 | private String mPassword; 120 | 121 | private String mTrustAll; 122 | 123 | private Context mContext; 124 | 125 | // UI references. 126 | private IconfiedEditText mUserView; 127 | 128 | private IconfiedEditText mPasswordText; 129 | 130 | private View mLoginFormView; 131 | 132 | private View mLoginStatusView; 133 | 134 | private TextView mLoginStatusMessageView; 135 | 136 | private CheckBox mTrustCheckBox; 137 | 138 | private AccountManager mAccountManager; 139 | 140 | private String mURL; 141 | 142 | private IconfiedEditText mURLText; 143 | 144 | private String mAccountname; 145 | 146 | private IconfiedEditText mAccountnameText; 147 | 148 | private String mUpdateInterval; 149 | 150 | private IconfiedEditText mUpdateIntervalView; 151 | 152 | private Drawable mGmailButton; 153 | 154 | private Drawable mClearButton; 155 | 156 | public AuthenticatorActivity() { 157 | super(); 158 | } 159 | 160 | @Override 161 | protected void onCreate(Bundle savedInstanceState) { 162 | super.onCreate(savedInstanceState); 163 | setContentView(R.layout.activity_authenticator); 164 | 165 | mAccountManager = AccountManager.get(this); 166 | 167 | // Set up the login form. 168 | mUser = getIntent().getStringExtra(EXTRA_EMAIL); 169 | mUserView = (IconfiedEditText) findViewById(R.id.user); 170 | mUserView.setText(mUser); 171 | mUserView.addClearButton(); 172 | 173 | mContext = getBaseContext(); 174 | App.setContext(mContext); 175 | mPasswordText = (IconfiedEditText) findViewById(R.id.password); 176 | mPasswordText.addClearButton(); 177 | mPasswordText 178 | .setOnEditorActionListener(new TextView.OnEditorActionListener() { 179 | @Override 180 | public boolean onEditorAction(TextView textView, int id, 181 | KeyEvent keyEvent) { 182 | if (id == R.id.login || id == EditorInfo.IME_NULL) { 183 | attemptLogin(); 184 | return true; 185 | } 186 | return false; 187 | } 188 | }); 189 | 190 | mURLText = (IconfiedEditText) findViewById(R.id.url); 191 | mURLText.addClearButton(); 192 | // if the URL start with "https" show the option to disable SSL host verification 193 | mURLText.addTextChangedListener(new TextWatcher() { 194 | @Override 195 | public void onTextChanged(CharSequence s, int start, int before, int count) { 196 | String url = ((EditText) findViewById(R.id.url)).getText().toString(); 197 | if (url.toLowerCase(Locale.getDefault()) 198 | .startsWith("https")) { 199 | (findViewById(R.id.trustall)).setVisibility(View.VISIBLE); 200 | } else { 201 | (findViewById(R.id.trustall)).setVisibility(View.GONE); 202 | } 203 | } 204 | 205 | @Override 206 | public void beforeTextChanged(CharSequence s, int start, int count, 207 | int after) { 208 | } 209 | 210 | @Override 211 | public void afterTextChanged(Editable s) { 212 | } 213 | }); 214 | 215 | mClearButton = getResources().getDrawable(android.R.drawable.ic_menu_close_clear_cancel); 216 | mGmailButton = getResources().getDrawable(R.drawable.ic_gmail); 217 | mAccountnameText = (IconfiedEditText) findViewById(R.id.accountname); 218 | mAccountnameText.addTextChangedListener(new TextWatcher() { 219 | @Override 220 | public void beforeTextChanged(CharSequence s, int start, int count, int after) { 221 | } 222 | 223 | @Override 224 | public void onTextChanged(CharSequence s, int start, int before, int count) { 225 | Drawable drawable = TextUtils.isEmpty(s.toString()) ? mGmailButton : mClearButton; 226 | mAccountnameText 227 | .setCompoundDrawablesWithIntrinsicBounds(null, null, drawable, null); 228 | } 229 | 230 | @Override 231 | public void afterTextChanged(Editable s) { 232 | } 233 | }); 234 | mAccountnameText.setDrawableClickListener(new DrawableClickListener() { 235 | @Override 236 | public void onClick(DrawablePosition target) { 237 | switch (target) { 238 | case RIGHT: 239 | if (TextUtils.isEmpty(mAccountnameText.getText().toString())) { 240 | mAccountnameText.setText(AccountUtility.getGoogleMail()); 241 | } else { 242 | mAccountnameText.setText(""); 243 | } 244 | } 245 | } 246 | }); 247 | 248 | mUpdateIntervalView = (IconfiedEditText) findViewById(R.id.updateinterval); 249 | mUpdateIntervalView.addClearButton(); 250 | 251 | mLoginFormView = findViewById(R.id.login_form); 252 | mLoginStatusView = findViewById(R.id.login_status); 253 | mLoginStatusMessageView = (TextView) findViewById(R.id.login_status_message); 254 | 255 | findViewById(R.id.sign_in_button).setOnClickListener( 256 | new View.OnClickListener() { 257 | @Override 258 | public void onClick(View view) { 259 | attemptLogin(); 260 | } 261 | } 262 | ); 263 | 264 | mTrustCheckBox = (CheckBox) findViewById(R.id.trustall); 265 | 266 | Account lcAccount = (Account) getIntent().getExtras().get(Constants.INVALID_CREDENTIALS_CHECK); 267 | 268 | if (lcAccount != null) { 269 | account = lcAccount; 270 | mAccountnameText.setEnabled(false); 271 | mUserView.setText(mAccountManager.getUserData(lcAccount, AuthenticatorActivity.USER_DATA_USERNAME)); 272 | mPasswordText.setText(mAccountManager.getPassword(lcAccount)); 273 | mURLText.setText(mAccountManager.getUserData(lcAccount, AuthenticatorActivity.USER_DATA_URL_KEY)); 274 | mAccountnameText.setText(lcAccount.name); 275 | mUpdateIntervalView.setText(mAccountManager.getUserData(lcAccount, AuthenticatorActivity.USER_DATA_UPDATE_INTERVAL)); 276 | String lcTrustAll = mAccountManager.getUserData(lcAccount, Constants.USER_DATA_TRUST_ALL_KEY); 277 | if (lcTrustAll.equals("false")) { 278 | mTrustCheckBox.setChecked(true); 279 | }else{ 280 | mTrustCheckBox.setChecked(false); 281 | } 282 | } 283 | } 284 | 285 | @Override 286 | public boolean onCreateOptionsMenu(Menu menu) { 287 | super.onCreateOptionsMenu(menu); 288 | return true; 289 | } 290 | 291 | /** 292 | * Attempts to sign in or register the account specified by the login form. 293 | * If there are form errors (invalid email, missing fields, etc.), the 294 | * errors are presented and no actual login attempt is made. 295 | */ 296 | public void attemptLogin() { 297 | if (mAuthTask != null) { 298 | return; 299 | } 300 | 301 | // Reset errors. 302 | mUserView.setError(null); 303 | mPasswordText.setError(null); 304 | 305 | // Store values at the time of the login attempt. 306 | mUser = mUserView.getText().toString(); 307 | mPassword = mPasswordText.getText().toString(); 308 | mURL = mURLText.getText().toString(); 309 | mAccountname = mAccountnameText.getText().toString(); 310 | mUpdateInterval = mUpdateIntervalView.getText().toString(); 311 | 312 | if (mTrustCheckBox.isChecked()) { 313 | mTrustAll = "false"; 314 | } else { 315 | mTrustAll = "true"; 316 | } 317 | 318 | 319 | boolean cancel = false; 320 | View focusView = null; 321 | if (account == null) { 322 | if (!mAccountname.equals("")) { 323 | Account TestAccount = new Account(mAccountname, ACCOUNT_TYPE); 324 | 325 | String TestUrl = mAccountManager 326 | .getUserData(TestAccount, AuthenticatorActivity.USER_DATA_URL_KEY); 327 | if (TestUrl != null) { 328 | mAccountnameText.setError(getString(R.string.error_account_already_in_use)); 329 | focusView = mAccountnameText; 330 | cancel = true; 331 | } 332 | } 333 | } 334 | 335 | // Check for a valid password. 336 | if (TextUtils.isEmpty(mPassword)) { 337 | mPasswordText.setError(getString(R.string.error_field_required)); 338 | focusView = mPasswordText; 339 | cancel = true; 340 | } 341 | 342 | // Check for a valid email address. 343 | if (TextUtils.isEmpty(mUser)) { 344 | mUserView.setError(getString(R.string.error_field_required)); 345 | focusView = mUserView; 346 | cancel = true; 347 | } 348 | 349 | 350 | if (TextUtils.isEmpty(mUpdateInterval)) { 351 | mUpdateInterval = "30"; 352 | } 353 | try { 354 | Integer.parseInt(mUpdateInterval); 355 | } catch (Exception e) { 356 | mUpdateIntervalView.setError(getString(R.string.error_invalid_number)); 357 | focusView = mUpdateIntervalView; 358 | cancel = true; 359 | } 360 | 361 | if (cancel) { 362 | // There was an error; don't attempt login and focus the first 363 | // form field with an error. 364 | focusView.requestFocus(); 365 | } else { 366 | // Show a progress spinner, and kick off a background task to 367 | // perform the user login attempt. 368 | mLoginStatusMessageView.setText(R.string.login_progress_signing_in); 369 | showProgress(true); 370 | mAuthTask = new UserLoginTask(); 371 | mAuthTask.setActivity(this); 372 | mAuthTask.execute((Void) null); 373 | } 374 | } 375 | 376 | /** 377 | * Shows the progress UI and hides the login form. 378 | */ 379 | @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2) 380 | private void showProgress(final boolean show) { 381 | // On Honeycomb MR2 we have the ViewPropertyAnimator APIs, which allow 382 | // for very easy animations. If available, use these APIs to fade-in 383 | // the progress spinner. 384 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) { 385 | int shortAnimTime = getResources().getInteger( 386 | android.R.integer.config_shortAnimTime); 387 | 388 | mLoginStatusView.setVisibility(View.VISIBLE); 389 | mLoginStatusView.animate().setDuration(shortAnimTime) 390 | .alpha(show ? 1 : 0) 391 | .setListener(new AnimatorListenerAdapter() { 392 | @Override 393 | public void onAnimationEnd(Animator animation) { 394 | mLoginStatusView.setVisibility(show ? View.VISIBLE 395 | : View.GONE); 396 | } 397 | }); 398 | 399 | mLoginFormView.setVisibility(View.VISIBLE); 400 | mLoginFormView.animate().setDuration(shortAnimTime) 401 | .alpha(show ? 0 : 1) 402 | .setListener(new AnimatorListenerAdapter() { 403 | @Override 404 | public void onAnimationEnd(Animator animation) { 405 | mLoginFormView.setVisibility(show ? View.GONE 406 | : View.VISIBLE); 407 | } 408 | }); 409 | } else { 410 | // The ViewPropertyAnimator APIs are not available, so simply show 411 | // and hide the relevant UI components. 412 | mLoginStatusView.setVisibility(show ? View.VISIBLE : View.GONE); 413 | mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE); 414 | } 415 | } 416 | 417 | 418 | protected enum LoginResult { 419 | MalformedURLException, 420 | GeneralSecurityException, 421 | UnkonwnException, 422 | WrongCredentials, 423 | InvalidResponse, 424 | WrongUrl, 425 | ConnectionRefused, 426 | Success_Calendar, 427 | Success_Collection, 428 | UNTRUSTED_CERT, 429 | Account_Already_In_Use 430 | } 431 | 432 | 433 | /** 434 | * Represents an asynchronous login/registration task used to authenticate 435 | * the user. 436 | */ 437 | public class UserLoginTask extends AsyncTask { 438 | private Activity activity; 439 | 440 | @Override 441 | protected LoginResult doInBackground(Void... params) { 442 | 443 | TestConnectionResult result = null; 444 | 445 | try { 446 | CaldavFacade facade = new CaldavFacade(mUser, mPassword, mURL, mTrustAll); 447 | String version = ""; 448 | try { 449 | version = mContext.getPackageManager() 450 | .getPackageInfo(mContext.getPackageName(), 0).versionName; 451 | } catch (NameNotFoundException e) { 452 | version = "unknown"; 453 | e.printStackTrace(); 454 | } 455 | facade.setVersion(version); 456 | result = facade.testConnection(); 457 | Log.i(TAG, "testConnection status=" + result); 458 | } catch (HttpHostConnectException e) { 459 | Log.w(TAG, "testConnection", e); 460 | return LoginResult.ConnectionRefused; 461 | } catch (MalformedURLException e) { 462 | Log.w(TAG, "testConnection", e); 463 | return LoginResult.MalformedURLException; 464 | } catch (UnsupportedEncodingException e) { 465 | Log.w(TAG, "testConnection", e); 466 | return LoginResult.UnkonwnException; 467 | } catch (ParserConfigurationException e) { 468 | Log.w(TAG, "testConnection", e); 469 | return LoginResult.UnkonwnException; 470 | } catch (SAXException e) { 471 | Log.w(TAG, "testConnection", e); 472 | return LoginResult.InvalidResponse; 473 | } catch (IOException e) { 474 | Log.w(TAG, "testConnection", e); 475 | return LoginResult.UnkonwnException; 476 | } catch (URISyntaxException e) { 477 | Log.w(TAG, "testConnection", e); 478 | return LoginResult.MalformedURLException; 479 | } 480 | 481 | if (result == null) { 482 | return LoginResult.UnkonwnException; 483 | } 484 | 485 | switch (result) { 486 | 487 | case SSL_ERROR: 488 | return LoginResult.UNTRUSTED_CERT; 489 | case SUCCESS: 490 | LoginResult Result = LoginResult.Success_Calendar; 491 | 492 | Account lcAccount = account; 493 | if (lcAccount == null) { 494 | if (mAccountname.equals("")) { 495 | lcAccount = new Account(mUser + ACCOUNT_NAME_SPLITTER + mURL, 496 | ACCOUNT_TYPE); 497 | } else { 498 | lcAccount = new Account(mAccountname, ACCOUNT_TYPE); 499 | } 500 | if (mAccountManager.addAccountExplicitly(lcAccount, mPassword, null)) { 501 | Log.v(TAG, "new account created"); 502 | final int updateFrequency = Integer.parseInt(mUpdateInterval) * 60; 503 | mAccountManager.setUserData(lcAccount, USER_DATA_URL_KEY, mURL); 504 | mAccountManager.setUserData(lcAccount, USER_DATA_USERNAME, mUser); 505 | mAccountManager.setUserData(lcAccount, USER_DATA_VERSION, 506 | CURRENT_USER_DATA_VERSION); 507 | mAccountManager.setUserData(lcAccount, Constants.USER_DATA_TRUST_ALL_KEY, 508 | mTrustAll); 509 | ContentResolver.setSyncAutomatically(lcAccount, "com.android.calendar", true); 510 | ContentResolver.addPeriodicSync(lcAccount, "com.android.calendar", new Bundle(), updateFrequency); 511 | } else { 512 | Log.v(TAG, "no new account created"); 513 | Result = LoginResult.Account_Already_In_Use; 514 | } 515 | } else { 516 | Log.v(TAG, "update account"); 517 | final int updateFrequency = Integer.parseInt(mUpdateInterval) * 60; 518 | 519 | mAccountManager.setPassword(lcAccount, mPassword); 520 | mAccountManager.setUserData(lcAccount, USER_DATA_URL_KEY, mURL); 521 | mAccountManager.setUserData(lcAccount, USER_DATA_USERNAME, mUser); 522 | mAccountManager.setUserData(lcAccount, USER_DATA_VERSION, 523 | CURRENT_USER_DATA_VERSION); 524 | mAccountManager.setUserData(lcAccount, Constants.USER_DATA_TRUST_ALL_KEY, 525 | mTrustAll); 526 | mAccountManager.updateCredentials(account, ACCOUNT_TYPE, null, this.activity, null, null); 527 | ContentResolver.setSyncAutomatically(lcAccount, "com.android.calendar", true); 528 | ContentResolver.addPeriodicSync(lcAccount, "com.android.calendar", new Bundle(), updateFrequency); 529 | } 530 | return Result; 531 | 532 | case WRONG_CREDENTIAL: 533 | return LoginResult.WrongCredentials; 534 | 535 | case WRONG_SERVER_STATUS: 536 | return LoginResult.InvalidResponse; 537 | 538 | case WRONG_URL: 539 | return LoginResult.WrongUrl; 540 | 541 | case WRONG_ANSWER: 542 | return LoginResult.InvalidResponse; 543 | 544 | default: 545 | return LoginResult.UnkonwnException; 546 | 547 | } 548 | 549 | } 550 | 551 | 552 | @Override 553 | protected void onPostExecute(final LoginResult result) { 554 | mAuthTask = null; 555 | showProgress(false); 556 | 557 | int duration = Toast.LENGTH_SHORT; 558 | Toast toast = null; 559 | 560 | switch (result) { 561 | case Success_Calendar: 562 | toast = Toast 563 | .makeText(getApplicationContext(), R.string.success_calendar, duration); 564 | toast.show(); 565 | finish(); 566 | break; 567 | 568 | case Success_Collection: 569 | toast = Toast.makeText(getApplicationContext(), R.string.success_collection, 570 | duration); 571 | toast.show(); 572 | finish(); 573 | break; 574 | 575 | case MalformedURLException: 576 | 577 | toast = Toast 578 | .makeText(getApplicationContext(), R.string.error_incorrect_url_format, 579 | duration); 580 | toast.show(); 581 | mURLText.setError(getString(R.string.error_incorrect_url_format)); 582 | mURLText.requestFocus(); 583 | break; 584 | case InvalidResponse: 585 | toast = Toast 586 | .makeText(getApplicationContext(), R.string.error_invalid_server_answer, 587 | duration); 588 | toast.show(); 589 | mURLText.setError(getString(R.string.error_invalid_server_answer)); 590 | mURLText.requestFocus(); 591 | break; 592 | case WrongUrl: 593 | toast = Toast 594 | .makeText(getApplicationContext(), R.string.error_wrong_url, duration); 595 | toast.show(); 596 | mURLText.setError(getString(R.string.error_wrong_url)); 597 | mURLText.requestFocus(); 598 | break; 599 | 600 | case GeneralSecurityException: 601 | break; 602 | case UnkonwnException: 603 | break; 604 | case WrongCredentials: 605 | mPasswordText.setError(getString(R.string.error_incorrect_password)); 606 | mPasswordText.requestFocus(); 607 | break; 608 | 609 | case ConnectionRefused: 610 | toast = Toast 611 | .makeText(getApplicationContext(), R.string.error_connection_refused, 612 | duration); 613 | toast.show(); 614 | mURLText.setError(getString(R.string.error_connection_refused)); 615 | mURLText.requestFocus(); 616 | break; 617 | case UNTRUSTED_CERT: 618 | toast = Toast.makeText(getApplicationContext(), 619 | getString(R.string.error_untrusted_certificate), duration); 620 | toast.show(); 621 | mURLText.setError(getString(R.string.error_ssl)); 622 | mURLText.requestFocus(); 623 | break; 624 | case Account_Already_In_Use: 625 | toast = Toast.makeText(getApplicationContext(), 626 | R.string.error_account_already_in_use, duration); 627 | toast.show(); 628 | mURLText.setError(getString(R.string.error_account_already_in_use)); 629 | mURLText.requestFocus(); 630 | break; 631 | default: 632 | toast = Toast.makeText(getApplicationContext(), R.string.error_unkown_error, 633 | duration); 634 | toast.show(); 635 | mURLText.setError(getString(R.string.error_unkown_error)); 636 | mURLText.requestFocus(); 637 | break; 638 | } 639 | 640 | 641 | } 642 | 643 | @Override 644 | protected void onCancelled() { 645 | mAuthTask = null; 646 | showProgress(false); 647 | } 648 | 649 | public void setActivity(Activity activity) { 650 | this.activity = activity; 651 | } 652 | } 653 | } -------------------------------------------------------------------------------- /ACalDAV/src/org/gege/caldavsyncadapter/authenticator/AuthenticatorStub.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Gerald Garcia 3 | * 4 | * This file is part of Andoid Caldav Sync Adapter Free. 5 | * 6 | * Andoid Caldav Sync Adapter Free is free software: you can redistribute 7 | * it and/or modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation, either version 3 of the 9 | * License, or at your option any later version. 10 | * 11 | * Andoid Caldav Sync Adapter Free is distributed in the hope that 12 | * it will be useful, but WITHOUT ANY WARRANTY; without even the implied 13 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with Andoid Caldav Sync Adapter Free. 18 | * If not, see . 19 | * 20 | */ 21 | 22 | package org.gege.caldavsyncadapter.authenticator; 23 | 24 | 25 | import android.accounts.AbstractAccountAuthenticator; 26 | import android.accounts.Account; 27 | import android.accounts.AccountAuthenticatorResponse; 28 | import android.accounts.AccountManager; 29 | import android.accounts.NetworkErrorException; 30 | import android.content.Context; 31 | import android.content.Intent; 32 | import android.os.Bundle; 33 | import android.util.Log; 34 | 35 | public class AuthenticatorStub extends AbstractAccountAuthenticator { 36 | 37 | private static final String TAG = "Authenticator"; 38 | 39 | private Context mContext; 40 | 41 | public AuthenticatorStub(Context context) { 42 | super(context); 43 | mContext = context; 44 | } 45 | 46 | @Override 47 | public Bundle addAccount(AccountAuthenticatorResponse response, 48 | String accountType, String authTokenType, 49 | String[] requiredFeatures, Bundle options) 50 | throws NetworkErrorException { 51 | 52 | Log.v(TAG, "addAccount()"); 53 | 54 | final Intent intent = new Intent(mContext, AuthenticatorActivity.class); 55 | intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response); 56 | final Bundle bundle = new Bundle(); 57 | bundle.putParcelable(AccountManager.KEY_INTENT, intent); 58 | return bundle; 59 | 60 | } 61 | 62 | @Override 63 | public Bundle confirmCredentials(AccountAuthenticatorResponse response, 64 | Account account, Bundle options) throws NetworkErrorException { 65 | return null; 66 | } 67 | 68 | @Override 69 | public Bundle editProperties(AccountAuthenticatorResponse response, 70 | String accountType) { 71 | return null; 72 | } 73 | 74 | @Override 75 | public Bundle getAuthToken(AccountAuthenticatorResponse response, 76 | Account account, String authTokenType, Bundle options) 77 | throws NetworkErrorException { 78 | return null; 79 | } 80 | 81 | @Override 82 | public String getAuthTokenLabel(String authTokenType) { 83 | return null; 84 | } 85 | 86 | @Override 87 | public Bundle hasFeatures(AccountAuthenticatorResponse response, 88 | Account account, String[] features) throws NetworkErrorException { 89 | return null; 90 | } 91 | 92 | @Override 93 | public Bundle updateCredentials(AccountAuthenticatorResponse response, 94 | Account account, String authTokenType, Bundle options) 95 | throws NetworkErrorException { 96 | return null; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /ACalDAV/src/org/gege/caldavsyncadapter/caldav/CaldavProtocolException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Gerald Garcia 3 | * 4 | * This file is part of Andoid Caldav Sync Adapter Free. 5 | * 6 | * Andoid Caldav Sync Adapter Free is free software: you can redistribute 7 | * it and/or modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation, either version 3 of the 9 | * License, or at your option any later version. 10 | * 11 | * Andoid Caldav Sync Adapter Free is distributed in the hope that 12 | * it will be useful, but WITHOUT ANY WARRANTY; without even the implied 13 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with Andoid Caldav Sync Adapter Free. 18 | * If not, see . 19 | * 20 | */ 21 | 22 | package org.gege.caldavsyncadapter.caldav; 23 | 24 | public class CaldavProtocolException extends Exception { 25 | 26 | /** 27 | * 28 | */ 29 | private static final long serialVersionUID = -8237099919427898671L; 30 | 31 | public CaldavProtocolException(String string) { 32 | super(string); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /ACalDAV/src/org/gege/caldavsyncadapter/caldav/EasySSLSocketFactory.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Gerald Garcia 3 | * 4 | * This file is part of Andoid Caldav Sync Adapter Free. 5 | * 6 | * Andoid Caldav Sync Adapter Free is free software: you can redistribute 7 | * it and/or modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation, either version 3 of the 9 | * License, or at your option any later version. 10 | * 11 | * Andoid Caldav Sync Adapter Free is distributed in the hope that 12 | * it will be useful, but WITHOUT ANY WARRANTY; without even the implied 13 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with Andoid Caldav Sync Adapter Free. 18 | * If not, see . 19 | * 20 | */ 21 | 22 | package org.gege.caldavsyncadapter.caldav; 23 | 24 | import android.net.SSLCertificateSocketFactory; 25 | import android.os.Build; 26 | import android.util.Log; 27 | 28 | import org.apache.http.conn.ConnectTimeoutException; 29 | import org.apache.http.conn.scheme.LayeredSocketFactory; 30 | import org.apache.http.conn.ssl.SSLSocketFactory; 31 | import org.apache.http.params.HttpConnectionParams; 32 | import org.apache.http.params.HttpParams; 33 | 34 | import java.io.IOException; 35 | import java.net.InetAddress; 36 | import java.net.InetSocketAddress; 37 | import java.net.Socket; 38 | import java.net.UnknownHostException; 39 | import java.security.KeyManagementException; 40 | import java.security.NoSuchAlgorithmException; 41 | import java.security.SecureRandom; 42 | import java.security.cert.CertificateException; 43 | import java.security.cert.X509Certificate; 44 | 45 | import javax.net.ssl.SSLContext; 46 | import javax.net.ssl.SSLSocket; 47 | import javax.net.ssl.TrustManager; 48 | import javax.net.ssl.X509TrustManager; 49 | 50 | 51 | public final class EasySSLSocketFactory implements 52 | LayeredSocketFactory { 53 | 54 | private static final String TAG = "TrustAllSSLSocketFactory"; 55 | 56 | private static final EasySSLSocketFactory DEFAULT_FACTORY = new EasySSLSocketFactory(); 57 | 58 | private SSLContext sslcontext; 59 | 60 | private javax.net.ssl.SSLSocketFactory socketfactory; 61 | 62 | private EasySSLSocketFactory() { 63 | super(); 64 | TrustManager[] tm = new TrustManager[]{new X509TrustManager() { 65 | 66 | @Override 67 | public void checkClientTrusted(X509Certificate[] chain, 68 | String authType) throws CertificateException { 69 | // do nothing 70 | } 71 | 72 | @Override 73 | public void checkServerTrusted(X509Certificate[] chain, 74 | String authType) throws CertificateException { 75 | // do nothing 76 | } 77 | 78 | @Override 79 | public X509Certificate[] getAcceptedIssuers() { 80 | return new X509Certificate[0]; 81 | } 82 | 83 | }}; 84 | try { 85 | this.sslcontext = SSLContext.getInstance(SSLSocketFactory.TLS); 86 | this.sslcontext.init(null, tm, new SecureRandom()); 87 | this.socketfactory = this.sslcontext.getSocketFactory(); 88 | } catch (NoSuchAlgorithmException e) { 89 | Log.e(this.getClass().getName(), e.getMessage()); 90 | } catch (KeyManagementException e) { 91 | Log.e(this.getClass().getName(), e.getMessage()); 92 | } 93 | } 94 | 95 | public static EasySSLSocketFactory getSocketFactory 96 | () { 97 | return DEFAULT_FACTORY; 98 | } 99 | 100 | @Override 101 | public Socket createSocket(Socket socket, String host, int port, 102 | boolean autoClose) throws IOException, UnknownHostException { 103 | 104 | SSLCertificateSocketFactory sslSocketFactory = 105 | (SSLCertificateSocketFactory) SSLCertificateSocketFactory.getInsecure(0, null); 106 | SSLSocket ssl = (SSLSocket)sslSocketFactory.createSocket(InetAddress.getByName(host), port); 107 | 108 | // enable TLSv1.1/1.2 if available 109 | // (see https://github.com/rfc2822/davdroid/issues/229) 110 | ssl.setEnabledProtocols(ssl.getSupportedProtocols()); 111 | 112 | // set up SNI before the handshake 113 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 114 | Log.i("SNISocketFactory", "Setting SNI hostname"); 115 | sslSocketFactory.setHostname(ssl, host); 116 | } else { 117 | Log.d("SNISocketFactory", "No documented SNI support on Android <4.2, trying with reflection"); 118 | try { 119 | java.lang.reflect.Method setHostnameMethod = ssl.getClass().getMethod("setHostname", String.class); 120 | setHostnameMethod.invoke(ssl, host); 121 | } catch (Exception e) { 122 | Log.w("SNISocketFactory", "SNI not useable", e); 123 | } 124 | } 125 | return ssl; 126 | } 127 | 128 | @Override 129 | public Socket connectSocket(Socket sock, String host, int port, 130 | InetAddress localAddress, int localPort, HttpParams params) 131 | throws IOException, UnknownHostException, ConnectTimeoutException { 132 | if (host == null) { 133 | throw new IllegalArgumentException( 134 | "Target host may not be null."); 135 | } 136 | if (params == null) { 137 | throw new IllegalArgumentException( 138 | "Parameters may not be null."); 139 | } 140 | 141 | SSLSocket sslsock = (SSLSocket) ((sock != null) ? sock 142 | : createSocket()); 143 | 144 | if ((localAddress != null) || (localPort > 0)) { 145 | 146 | // we need to bind explicitly 147 | if (localPort < 0) { 148 | localPort = 0; // indicates "any" 149 | } 150 | 151 | InetSocketAddress isa = new InetSocketAddress(localAddress, 152 | localPort); 153 | sslsock.bind(isa); 154 | } 155 | 156 | int connTimeout = HttpConnectionParams.getConnectionTimeout(params); 157 | int soTimeout = HttpConnectionParams.getSoTimeout(params); 158 | 159 | InetSocketAddress remoteAddress; 160 | remoteAddress = new InetSocketAddress(host, port); 161 | 162 | sslsock.connect(remoteAddress, connTimeout); 163 | 164 | sslsock.setSoTimeout(soTimeout); 165 | 166 | return sslsock; 167 | } 168 | 169 | @Override 170 | public Socket createSocket() throws IOException { 171 | // the cast makes sure that the factory is working as expected 172 | return (SSLSocket) this.socketfactory.createSocket(); 173 | } 174 | 175 | @Override 176 | public boolean isSecure(Socket sock) throws IllegalArgumentException { 177 | return true; 178 | } 179 | 180 | } -------------------------------------------------------------------------------- /ACalDAV/src/org/gege/caldavsyncadapter/caldav/EasyX509TrustManager.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Gerald Garcia 3 | * 4 | * This file is part of Andoid Caldav Sync Adapter Free. 5 | * 6 | * Andoid Caldav Sync Adapter Free is free software: you can redistribute 7 | * it and/or modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation, either version 3 of the 9 | * License, or at your option any later version. 10 | * 11 | * Andoid Caldav Sync Adapter Free is distributed in the hope that 12 | * it will be useful, but WITHOUT ANY WARRANTY; without even the implied 13 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with Andoid Caldav Sync Adapter Free. 18 | * If not, see . 19 | * 20 | */ 21 | 22 | package org.gege.caldavsyncadapter.caldav; 23 | 24 | /* 25 | * Licensed to the Apache Software Foundation (ASF) under one 26 | * or more contributor license agreements. See the NOTICE file 27 | * distributed with this work for additional information 28 | * regarding copyright ownership. The ASF licenses this file 29 | * to you under the Apache License, Version 2.0 (the 30 | * "License"); you may not use this file except in compliance 31 | * with the License. You may obtain a copy of the License at 32 | * 33 | * http://www.apache.org/licenses/LICENSE-2.0 34 | * 35 | * Unless required by applicable law or agreed to in writing, 36 | * software distributed under the License is distributed on an 37 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 38 | * KIND, either express or implied. See the License for the 39 | * specific language governing permissions and limitations 40 | * under the License. 41 | */ 42 | 43 | import java.security.KeyStore; 44 | import java.security.KeyStoreException; 45 | import java.security.NoSuchAlgorithmException; 46 | import java.security.cert.CertificateException; 47 | import java.security.cert.X509Certificate; 48 | 49 | import javax.net.ssl.TrustManager; 50 | import javax.net.ssl.TrustManagerFactory; 51 | import javax.net.ssl.X509TrustManager; 52 | 53 | /** 54 | * @author olamy 55 | * @version $Id: EasyX509TrustManager.java 765355 2009-04-15 20:59:07Z evenisse $ 56 | * @since 1.2.3 57 | */ 58 | public class EasyX509TrustManager 59 | implements X509TrustManager { 60 | 61 | private X509TrustManager standardTrustManager = null; 62 | 63 | /** 64 | * Constructor for EasyX509TrustManager. 65 | */ 66 | public EasyX509TrustManager(KeyStore keystore) 67 | throws NoSuchAlgorithmException, KeyStoreException { 68 | super(); 69 | TrustManagerFactory factory = TrustManagerFactory 70 | .getInstance(TrustManagerFactory.getDefaultAlgorithm()); 71 | factory.init(keystore); 72 | TrustManager[] trustmanagers = factory.getTrustManagers(); 73 | if (trustmanagers.length == 0) { 74 | throw new NoSuchAlgorithmException("no trust manager found"); 75 | } 76 | this.standardTrustManager = (X509TrustManager) trustmanagers[0]; 77 | } 78 | 79 | /** 80 | * @see javax.net.ssl.X509TrustManager#checkClientTrusted(X509Certificate[], String authType) 81 | */ 82 | public void checkClientTrusted(X509Certificate[] certificates, String authType) 83 | throws CertificateException { 84 | standardTrustManager.checkClientTrusted(certificates, authType); 85 | } 86 | 87 | /** 88 | * @see javax.net.ssl.X509TrustManager#checkServerTrusted(X509Certificate[], String authType) 89 | */ 90 | public void checkServerTrusted(X509Certificate[] certificates, String authType) 91 | throws CertificateException { 92 | if ((certificates != null) && (certificates.length == 1)) { 93 | certificates[0].checkValidity(); 94 | } else { 95 | standardTrustManager.checkServerTrusted(certificates, authType); 96 | } 97 | } 98 | 99 | /** 100 | * @see javax.net.ssl.X509TrustManager#getAcceptedIssuers() 101 | */ 102 | public X509Certificate[] getAcceptedIssuers() { 103 | return this.standardTrustManager.getAcceptedIssuers(); 104 | } 105 | 106 | } -------------------------------------------------------------------------------- /ACalDAV/src/org/gege/caldavsyncadapter/caldav/TlsSniSocketFactory.java: -------------------------------------------------------------------------------- 1 | package org.gege.caldavsyncadapter.caldav; 2 | 3 | import android.annotation.TargetApi; 4 | import android.net.SSLCertificateSocketFactory; 5 | import android.os.Build; 6 | import android.util.Log; 7 | 8 | import org.apache.http.conn.scheme.LayeredSocketFactory; 9 | import org.apache.http.conn.ssl.StrictHostnameVerifier; 10 | import org.apache.http.params.HttpParams; 11 | 12 | import java.io.IOException; 13 | import java.net.InetAddress; 14 | import java.net.Socket; 15 | 16 | import javax.net.ssl.HostnameVerifier; 17 | import javax.net.ssl.SSLPeerUnverifiedException; 18 | import javax.net.ssl.SSLSession; 19 | import javax.net.ssl.SSLSocket; 20 | 21 | /** 22 | * Created by enrico on 07/06/15. 23 | */ 24 | @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) 25 | public class TlsSniSocketFactory implements LayeredSocketFactory { 26 | private static final String TAG = "SNISocketFactory"; 27 | 28 | final static HostnameVerifier hostnameVerifier = new StrictHostnameVerifier(); 29 | 30 | 31 | // Plain TCP/IP (layer below TLS) 32 | 33 | @Override 34 | public Socket connectSocket(Socket s, String host, int port, InetAddress localAddress, 35 | int localPort, HttpParams params) throws IOException { 36 | return null; 37 | } 38 | 39 | @Override 40 | public Socket createSocket() throws IOException { 41 | return null; 42 | } 43 | 44 | @Override 45 | public boolean isSecure(Socket s) throws IllegalArgumentException { 46 | return s instanceof SSLSocket && s.isConnected(); 47 | } 48 | 49 | 50 | // TLS layer 51 | 52 | @Override 53 | public Socket createSocket(Socket plainSocket, String host, int port, boolean autoClose) 54 | throws IOException { 55 | if (autoClose) { 56 | // we don't need the plainSocket 57 | plainSocket.close(); 58 | } 59 | 60 | // create and connect SSL socket, but don't do hostname/certificate verification yet 61 | SSLCertificateSocketFactory sslSocketFactory = (SSLCertificateSocketFactory) SSLCertificateSocketFactory.getDefault(0); 62 | SSLSocket ssl = (SSLSocket)sslSocketFactory.createSocket(InetAddress.getByName(host), port); 63 | 64 | // enable TLSv1.1/1.2 if available 65 | // (see https://github.com/rfc2822/davdroid/issues/229) 66 | ssl.setEnabledProtocols(ssl.getSupportedProtocols()); 67 | 68 | // set up SNI before the handshake 69 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 70 | Log.i(TAG, "Setting SNI hostname"); 71 | sslSocketFactory.setHostname(ssl, host); 72 | } else { 73 | Log.d(TAG, "No documented SNI support on Android <4.2, trying with reflection"); 74 | try { 75 | java.lang.reflect.Method setHostnameMethod = ssl.getClass().getMethod("setHostname", String.class); 76 | setHostnameMethod.invoke(ssl, host); 77 | } catch (Exception e) { 78 | Log.w(TAG, "SNI not useable", e); 79 | } 80 | } 81 | 82 | // verify hostname and certificate 83 | SSLSession session = ssl.getSession(); 84 | if (!hostnameVerifier.verify(host, session)) 85 | throw new SSLPeerUnverifiedException("Cannot verify hostname: " + host); 86 | 87 | Log.i(TAG, "Established " + session.getProtocol() + " connection with " + session.getPeerHost() + 88 | " using " + session.getCipherSuite()); 89 | 90 | return ssl; 91 | } 92 | } -------------------------------------------------------------------------------- /ACalDAV/src/org/gege/caldavsyncadapter/caldav/discovery/DefaultDiscoveryStrategy.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Gerald Garcia 3 | * 4 | * This file is part of Andoid Caldav Sync Adapter Free. 5 | * 6 | * Andoid Caldav Sync Adapter Free is free software: you can redistribute 7 | * it and/or modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation, either version 3 of the 9 | * License, or at your option any later version. 10 | * 11 | * Andoid Caldav Sync Adapter Free is distributed in the hope that 12 | * it will be useful, but WITHOUT ANY WARRANTY; without even the implied 13 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with Andoid Caldav Sync Adapter Free. 18 | * If not, see . 19 | * 20 | */ 21 | package org.gege.caldavsyncadapter.caldav.discovery; 22 | 23 | import java.io.UnsupportedEncodingException; 24 | import java.net.URI; 25 | 26 | import org.apache.http.HttpHost; 27 | import org.apache.http.client.methods.HttpDelete; 28 | import org.apache.http.client.methods.HttpPut; 29 | import org.apache.http.client.methods.HttpUriRequest; 30 | import org.apache.http.entity.StringEntity; 31 | import org.gege.caldavsyncadapter.caldav.http.HttpPropFind; 32 | import org.gege.caldavsyncadapter.caldav.http.HttpReport; 33 | 34 | public class DefaultDiscoveryStrategy implements DiscoveryStrategy { 35 | 36 | @Override 37 | public boolean supportsTargetHost(HttpHost targetHost) { 38 | return true; 39 | } 40 | 41 | @Override 42 | public HttpPropFind createPropFindRequest(URI uri, String data, int depth, HttpHost targetHost) { 43 | HttpPropFind request = new HttpPropFind(); 44 | request.setURI(uri); 45 | try { 46 | request.setEntity(new StringEntity(data)); 47 | } catch (UnsupportedEncodingException e) { 48 | throw new AssertionError("UTF-8 is unknown"); 49 | } 50 | 51 | injectDefaultHeaders(request, depth, targetHost); 52 | return request; 53 | } 54 | 55 | @Override 56 | public HttpReport createReportRequest(URI uri, String data, int depth, 57 | HttpHost targetHost) { 58 | HttpReport request = new HttpReport(); 59 | request.setURI(uri); 60 | try { 61 | request.setEntity(new StringEntity(data)); 62 | } catch (UnsupportedEncodingException e) { 63 | throw new AssertionError("UTF-8 is unknown"); 64 | } 65 | 66 | injectDefaultHeaders(request, depth, targetHost); 67 | return request; 68 | } 69 | 70 | private void injectDefaultHeaders(HttpUriRequest request, int depth, HttpHost targetHost) { 71 | request.setHeader("Host", 72 | targetHost.getHostName() + ":" + String.valueOf(targetHost.getPort())); 73 | request.setHeader("Depth", Integer.toString(depth)); 74 | request.setHeader("Content-Type", "application/xml;charset=\"UTF-8\""); 75 | 76 | } 77 | 78 | @Override 79 | public HttpDelete createDeleteRequest(URI uri, HttpHost targetHost) { 80 | HttpDelete request = new HttpDelete(); 81 | request.setURI(uri); 82 | injectDefaultHeaders(request, 0, targetHost); 83 | request.removeHeaders("Depth"); 84 | return request; 85 | } 86 | 87 | @Override 88 | public HttpPut createPutRequest(URI uri, String data, int depth, 89 | HttpHost targetHost) { 90 | HttpPut request = new HttpPut(); 91 | request.setURI(uri); 92 | injectDefaultHeaders(request, depth, targetHost); 93 | request.removeHeaders("Depth"); 94 | request.setHeader("Content-Type", "text/calendar; charset=utf-8"); 95 | try { 96 | request.setEntity(new StringEntity(data, "UTF-8")); 97 | } catch (UnsupportedEncodingException e) { 98 | throw new AssertionError("UTF-8 is unknown"); 99 | } 100 | return request; 101 | } 102 | 103 | } 104 | -------------------------------------------------------------------------------- /ACalDAV/src/org/gege/caldavsyncadapter/caldav/discovery/DiscoveryStrategy.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Gerald Garcia 3 | * 4 | * This file is part of Andoid Caldav Sync Adapter Free. 5 | * 6 | * Andoid Caldav Sync Adapter Free is free software: you can redistribute 7 | * it and/or modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation, either version 3 of the 9 | * License, or at your option any later version. 10 | * 11 | * Andoid Caldav Sync Adapter Free is distributed in the hope that 12 | * it will be useful, but WITHOUT ANY WARRANTY; without even the implied 13 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with Andoid Caldav Sync Adapter Free. 18 | * If not, see . 19 | * 20 | */ 21 | package org.gege.caldavsyncadapter.caldav.discovery; 22 | 23 | import java.net.URI; 24 | 25 | import org.apache.http.HttpHost; 26 | import org.apache.http.client.methods.HttpDelete; 27 | import org.apache.http.client.methods.HttpPut; 28 | import org.gege.caldavsyncadapter.caldav.http.HttpPropFind; 29 | import org.gege.caldavsyncadapter.caldav.http.HttpReport; 30 | 31 | /** 32 | * This interface deals with the preparation of requests. 33 | * Some hosts/server implementations have their peculiarities 34 | * that an implementation can challenge. 35 | */ 36 | public interface DiscoveryStrategy { 37 | 38 | /** 39 | * method is used to determine a matching strategy implementation 40 | * 41 | * An implementation shall only return true, if it supports host specific 42 | * features. 43 | * 44 | * @param targetHost the host 45 | * @return true if this strategy instance supports the given host 46 | */ 47 | boolean supportsTargetHost(HttpHost targetHost); 48 | 49 | /** 50 | * create a strategy specific version of a PROPFIND request 51 | * 52 | * @param uri the target uri 53 | * @param data the data payload 54 | * @param depth the "Depth" header value 55 | * @param targetHost the target host, used for "Host" header 56 | * @return the prepared request 57 | */ 58 | HttpPropFind createPropFindRequest(URI uri, String data, int depth, HttpHost targetHost); 59 | 60 | /** 61 | * create a strategy specific version of a Report request 62 | * 63 | * @param uri the target uri 64 | * @param data the data payload 65 | * @param depth the "Depth" header value 66 | * @param targetHost the target host, used for "Host" header 67 | * @return the prepared request 68 | */ 69 | HttpReport createReportRequest(URI uri, String data, int depth, 70 | HttpHost targetHost); 71 | 72 | /** 73 | * create a strategy specific version of a DELETE request 74 | * 75 | * @param uri the target uri 76 | * @param targetHost the target host, used for "Host" header 77 | * @return the prepared request 78 | */ 79 | HttpDelete createDeleteRequest(URI uri, HttpHost targetHost); 80 | 81 | /** 82 | * create a strategy specific version of a PUT request 83 | * 84 | * @param uri the target uri 85 | * @param data the data payload 86 | * @param depth the "Depth" header value 87 | * @param targetHost the target host, used for "Host" header 88 | * @return the prepared request 89 | */ 90 | HttpPut createPutRequest(URI uri, String data, int depth, 91 | HttpHost targetHost); 92 | 93 | } 94 | -------------------------------------------------------------------------------- /ACalDAV/src/org/gege/caldavsyncadapter/caldav/discovery/GoogleDiscoveryStrategy.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Gerald Garcia 3 | * 4 | * This file is part of Andoid Caldav Sync Adapter Free. 5 | * 6 | * Andoid Caldav Sync Adapter Free is free software: you can redistribute 7 | * it and/or modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation, either version 3 of the 9 | * License, or at your option any later version. 10 | * 11 | * Andoid Caldav Sync Adapter Free is distributed in the hope that 12 | * it will be useful, but WITHOUT ANY WARRANTY; without even the implied 13 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with Andoid Caldav Sync Adapter Free. 18 | * If not, see . 19 | * 20 | */ 21 | package org.gege.caldavsyncadapter.caldav.discovery; 22 | 23 | import java.net.URI; 24 | 25 | import org.apache.http.HttpHost; 26 | import org.apache.http.client.methods.HttpDelete; 27 | import org.apache.http.client.methods.HttpPut; 28 | import org.apache.http.client.methods.HttpUriRequest; 29 | import org.gege.caldavsyncadapter.caldav.http.HttpPropFind; 30 | import org.gege.caldavsyncadapter.caldav.http.HttpReport; 31 | 32 | public class GoogleDiscoveryStrategy extends DefaultDiscoveryStrategy { 33 | 34 | @Override 35 | public boolean supportsTargetHost(HttpHost targetHost) { 36 | if (targetHost != null && targetHost.getHostName() != null) { 37 | return targetHost.getHostName().contains("google.com"); 38 | } 39 | return false; 40 | } 41 | 42 | @Override 43 | public HttpPropFind createPropFindRequest(URI uri, String data, int depth, 44 | HttpHost targetHost) { 45 | HttpPropFind result = super.createPropFindRequest(uri, data, depth, targetHost); 46 | filterHostSpecifics(targetHost, result); 47 | return result; 48 | } 49 | 50 | @Override 51 | public HttpReport createReportRequest(URI uri, String data, int depth, 52 | HttpHost targetHost) { 53 | HttpReport result = super.createReportRequest(uri, data, depth, targetHost); 54 | filterHostSpecifics(targetHost, result); 55 | return result; 56 | } 57 | 58 | @Override 59 | public HttpDelete createDeleteRequest(URI uri, HttpHost targetHost) { 60 | HttpDelete result = super.createDeleteRequest(uri, targetHost); 61 | filterHostSpecifics(targetHost, result); 62 | return result; 63 | } 64 | 65 | @Override 66 | public HttpPut createPutRequest(URI uri, String data, int depth, 67 | HttpHost targetHost) { 68 | HttpPut result = super.createPutRequest(uri, data, depth, targetHost); 69 | filterHostSpecifics(targetHost, result); 70 | return result; 71 | } 72 | 73 | private HttpUriRequest filterHostSpecifics(HttpHost targetHost, HttpUriRequest result) { 74 | result.setHeader("Host", targetHost.getHostName()); 75 | return result; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /ACalDAV/src/org/gege/caldavsyncadapter/caldav/entities/CalendarList.java: -------------------------------------------------------------------------------- 1 | package org.gege.caldavsyncadapter.caldav.entities; 2 | 3 | import android.accounts.Account; 4 | import android.content.ContentProviderClient; 5 | import android.database.Cursor; 6 | import android.net.Uri; 7 | import android.os.RemoteException; 8 | import android.provider.CalendarContract.Calendars; 9 | import android.util.Log; 10 | 11 | import org.gege.caldavsyncadapter.caldav.entities.DavCalendar.CalendarSource; 12 | import org.gege.caldavsyncadapter.syncadapter.notifications.NotificationsHelper; 13 | 14 | import java.net.URI; 15 | import java.util.ArrayList; 16 | 17 | //import org.gege.caldavsyncadapter.CalendarColors; 18 | //import android.content.ContentUris; 19 | //import android.content.ContentValues; 20 | //import android.util.Log; 21 | 22 | public class CalendarList { 23 | // private static final String TAG = "CalendarList"; 24 | 25 | public CalendarSource Source = CalendarSource.undefined; 26 | 27 | public String ServerUrl = ""; 28 | 29 | private java.util.ArrayList mList = new java.util.ArrayList(); 30 | 31 | private Account mAccount = null; 32 | 33 | private ContentProviderClient mProvider = null; 34 | 35 | public CalendarList(Account account, ContentProviderClient provider, CalendarSource source, 36 | String serverUrl) { 37 | this.mAccount = account; 38 | this.mProvider = provider; 39 | this.Source = source; 40 | this.ServerUrl = serverUrl; 41 | } 42 | 43 | public DavCalendar getCalendarByURI(URI calendarURI) { 44 | DavCalendar lcResult = null; 45 | 46 | for (DavCalendar Item : mList) { 47 | if (Item.getURI().equals(calendarURI)) { 48 | lcResult = Item; 49 | } 50 | } 51 | 52 | return lcResult; 53 | } 54 | 55 | public DavCalendar getCalendarByAndroidUri(Uri androidCalendarUri) { 56 | DavCalendar lcResult = null; 57 | 58 | for (DavCalendar lcDavCalendars : mList) { 59 | if (lcDavCalendars.getAndroidCalendarUri().equals(androidCalendarUri)) { 60 | lcResult = lcDavCalendars; 61 | } 62 | } 63 | 64 | return lcResult; 65 | } 66 | 67 | /** 68 | * function to get all calendars from client side android 69 | */ 70 | public boolean readCalendarFromClient() { 71 | boolean lcResult = false; 72 | Cursor cur = null; 73 | 74 | Uri uri = Calendars.CONTENT_URI; 75 | 76 | /* COMPAT: in the past, the serverurl was not stored within a calendar. (see #98) 77 | * so there was no chance to see which calendars belongs to a named account. 78 | * username + serverurl have to be unique 79 | * ((DavCalendar.SERVERURL = ?) OR (DavCalendar.SERVERURL IS NULL)) 80 | */ 81 | String selection = "((" 82 | + Calendars.ACCOUNT_NAME + " = ?) AND " + 83 | "(" + Calendars.ACCOUNT_TYPE + " = ?))"; 84 | 85 | String[] selectionArgs = new String[]{ 86 | mAccount.name, 87 | mAccount.type 88 | }; 89 | 90 | String[] projection = new String[]{ 91 | Calendars._ID, 92 | Calendars.NAME, 93 | Calendars.ACCOUNT_NAME, 94 | Calendars.ACCOUNT_TYPE 95 | }; 96 | 97 | // Submit the query and get a Cursor object back. 98 | try { 99 | cur = mProvider.query(uri, null, selection, selectionArgs, Calendars._ID + " ASC"); 100 | } catch (RemoteException e) { 101 | Log.e(this.getClass().getCanonicalName(), e.getMessage()); 102 | } 103 | if (cur != null) { 104 | while (cur.moveToNext()) { 105 | mList.add(new DavCalendar(mAccount, mProvider, cur, this.Source, this.ServerUrl)); 106 | } 107 | cur.close(); 108 | lcResult = true; 109 | } 110 | 111 | return lcResult; 112 | } 113 | 114 | public boolean deleteCalendarOnClientSideOnly(android.content.Context context) { 115 | boolean lcResult = false; 116 | 117 | for (DavCalendar androidCalendar : this.mList) { 118 | if (!androidCalendar.foundServerSide) { 119 | NotificationsHelper.signalSyncErrors(context, "CalDAV Sync Adapter", 120 | "calendar deleted: " + androidCalendar 121 | .getCalendarDisplayName()); 122 | androidCalendar.deleteAndroidCalendar(); 123 | } 124 | } 125 | 126 | return lcResult; 127 | } 128 | 129 | public void addCalendar(DavCalendar item) { 130 | item.setAccount(this.mAccount); 131 | item.setProvider(this.mProvider); 132 | item.ServerUrl = this.ServerUrl; 133 | this.mList.add(item); 134 | } 135 | 136 | public ArrayList getCalendarList() { 137 | return this.mList; 138 | } 139 | 140 | public void setAccount(Account account) { 141 | this.mAccount = account; 142 | } 143 | 144 | public void setProvider(ContentProviderClient provider) { 145 | this.mProvider = provider; 146 | } 147 | 148 | public ArrayList getNotifyList() { 149 | ArrayList lcResult = new ArrayList(); 150 | 151 | for (DavCalendar cal : this.mList) { 152 | lcResult.addAll(cal.getNotifyList()); 153 | } 154 | 155 | return lcResult; 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /ACalDAV/src/org/gege/caldavsyncadapter/caldav/entities/DavCalendar.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Gerald Garcia, Timo Berger 3 | * 4 | * This file is part of Andoid Caldav Sync Adapter Free. 5 | * 6 | * Andoid Caldav Sync Adapter Free is free software: you can redistribute 7 | * it and/or modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation, either version 3 of the 9 | * License, or at your option any later version. 10 | * 11 | * Andoid Caldav Sync Adapter Free is distributed in the hope that 12 | * it will be useful, but WITHOUT ANY WARRANTY; without even the implied 13 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with Andoid Caldav Sync Adapter Free. 18 | * If not, see . 19 | * 20 | */ 21 | 22 | package org.gege.caldavsyncadapter.caldav.entities; 23 | 24 | import android.accounts.Account; 25 | import android.content.ContentProviderClient; 26 | import android.content.ContentUris; 27 | import android.content.ContentValues; 28 | import android.content.SyncStats; 29 | import android.database.Cursor; 30 | import android.net.Uri; 31 | import android.os.RemoteException; 32 | import android.provider.CalendarContract; 33 | import android.provider.CalendarContract.Calendars; 34 | import android.provider.CalendarContract.Events; 35 | import android.util.Log; 36 | 37 | import org.apache.http.client.ClientProtocolException; 38 | import org.gege.caldavsyncadapter.CalendarColors; 39 | import org.gege.caldavsyncadapter.Event; 40 | import org.gege.caldavsyncadapter.android.entities.AndroidEvent; 41 | import org.gege.caldavsyncadapter.caldav.CaldavFacade; 42 | import org.gege.caldavsyncadapter.syncadapter.SyncAdapter; 43 | import org.gege.caldavsyncadapter.syncadapter.notifications.NotificationsHelper; 44 | import org.xml.sax.SAXException; 45 | 46 | import java.io.IOException; 47 | import java.net.URI; 48 | import java.net.URISyntaxException; 49 | import java.util.ArrayList; 50 | import java.util.regex.Matcher; 51 | import java.util.regex.Pattern; 52 | 53 | import javax.xml.parsers.ParserConfigurationException; 54 | 55 | public class DavCalendar { 56 | 57 | private static final String TAG = "Calendar"; 58 | 59 | /** 60 | * stores the CTAG of a calendar 61 | */ 62 | public static String CTAG = Calendars.CAL_SYNC1; 63 | 64 | /** 65 | * stores the URI of a calendar 66 | * example: http://caldav.example.com/calendarserver.php/calendars/username/calendarname 67 | */ 68 | public static String URI = Calendars._SYNC_ID; 69 | 70 | public static String SERVERURL = Calendars.CAL_SYNC2; 71 | 72 | /** 73 | * the event transformed into ContentValues 74 | */ 75 | public ContentValues ContentValues = new ContentValues(); 76 | 77 | public boolean foundServerSide = false; 78 | 79 | public boolean foundClientSide = false; 80 | 81 | public CalendarSource Source = CalendarSource.undefined; 82 | 83 | public String ServerUrl = ""; 84 | 85 | private String strCalendarColor = ""; 86 | 87 | private ArrayList mNotifyList = new ArrayList(); 88 | 89 | private Account mAccount = null; 90 | 91 | private ContentProviderClient mProvider = null; 92 | 93 | private ArrayList mCalendarEvents = new ArrayList(); 94 | 95 | private int mTagCounter = 1; 96 | 97 | /** 98 | * empty constructor 99 | */ 100 | public DavCalendar(CalendarSource source) { 101 | this.Source = source; 102 | } 103 | 104 | /** 105 | * creates an new instance from a cursor 106 | * 107 | * @param cur must be a cursor from "ContentProviderClient" with Uri Calendars.CONTENT_URI 108 | */ 109 | public DavCalendar(Account account, ContentProviderClient provider, Cursor cur, 110 | CalendarSource source, String serverUrl) { 111 | this.mAccount = account; 112 | this.mProvider = provider; 113 | this.foundClientSide = true; 114 | this.Source = source; 115 | this.ServerUrl = serverUrl; 116 | 117 | String strSyncID = cur.getString(cur.getColumnIndex(Calendars._SYNC_ID)); 118 | String strName = cur.getString(cur.getColumnIndex(Calendars.NAME)); 119 | String strDisplayName = cur.getString(cur.getColumnIndex(Calendars.CALENDAR_DISPLAY_NAME)); 120 | String strCTAG = cur.getString(cur.getColumnIndex(DavCalendar.CTAG)); 121 | String strServerUrl = cur.getString(cur.getColumnIndex(DavCalendar.SERVERURL)); 122 | String strCalendarColor = cur.getString(cur.getColumnIndex(Calendars.CALENDAR_COLOR)); 123 | int intAndroidCalendarId = cur.getInt(cur.getColumnIndex(Calendars._ID)); 124 | 125 | this.setCalendarName(strName); 126 | this.setCalendarDisplayName(strDisplayName); 127 | this.setCTag(strCTAG, false); 128 | this.setAndroidCalendarId(intAndroidCalendarId); 129 | this.setCalendarColor(Integer.parseInt(strCalendarColor)); 130 | 131 | if (strSyncID == null) { 132 | this.correctSyncID(strName); 133 | strSyncID = strName; 134 | } 135 | if (strServerUrl == null) { 136 | this.correctServerUrl(serverUrl); 137 | } 138 | URI uri = null; 139 | try { 140 | uri = new URI(strSyncID); 141 | } catch (URISyntaxException e) { 142 | Log.e(getcTag(), e.getMessage()); 143 | } 144 | this.setURI(uri); 145 | } 146 | 147 | private static Uri asSyncAdapter(Uri uri, String account, String accountType) { 148 | return uri.buildUpon() 149 | .appendQueryParameter(android.provider.CalendarContract.CALLER_IS_SYNCADAPTER, 150 | "true") 151 | .appendQueryParameter(Calendars.ACCOUNT_NAME, account) 152 | .appendQueryParameter(Calendars.ACCOUNT_TYPE, accountType).build(); 153 | } 154 | 155 | /** 156 | * example: http://caldav.example.com/calendarserver.php/calendars/username/calendarname 157 | */ 158 | public URI getURI() { 159 | String strUri = this.getContentValueAsString(DavCalendar.URI); 160 | URI result = null; 161 | try { 162 | result = new URI(strUri); 163 | } catch (URISyntaxException e) { 164 | Log.e(getcTag(), e.getMessage()); 165 | } 166 | return result; 167 | } 168 | 169 | /** 170 | * example: http://caldav.example.com/calendarserver.php/calendars/username/calendarname 171 | */ 172 | public void setURI(URI uri) { 173 | this.setContentValueAsString(DavCalendar.URI, uri.toString()); 174 | } 175 | 176 | /** 177 | * example: Cleartext Display Name 178 | */ 179 | public String getCalendarDisplayName() { 180 | return this.getContentValueAsString(Calendars.CALENDAR_DISPLAY_NAME); 181 | } 182 | 183 | /** 184 | * example: Cleartext Display Name 185 | */ 186 | public void setCalendarDisplayName(String displayName) { 187 | this.setContentValueAsString(Calendars.CALENDAR_DISPLAY_NAME, displayName); 188 | } 189 | 190 | /** 191 | * example: 1143 192 | */ 193 | public void setCTag(String cTag, boolean Update) { 194 | this.setContentValueAsString(DavCalendar.CTAG, cTag); 195 | if (Update) { 196 | try { 197 | this.updateAndroidCalendar(this.getAndroidCalendarUri(), CTAG, cTag); 198 | } catch (RemoteException e) { 199 | e.printStackTrace(); 200 | } 201 | } 202 | } 203 | 204 | /** 205 | * example: 1143 206 | */ 207 | public String getcTag() { 208 | return this.getContentValueAsString(DavCalendar.CTAG); 209 | } 210 | 211 | /** 212 | * example: #FFCCAA 213 | */ 214 | public String getCalendarColorAsString() { 215 | return this.strCalendarColor; 216 | } 217 | 218 | /** 219 | * example: #FFCCAA 220 | */ 221 | public void setCalendarColorAsString(String color) { 222 | int maxlen = 6; 223 | 224 | this.strCalendarColor = color; 225 | if (!color.equals("")) { 226 | String strColor = color.replace("#", ""); 227 | if (strColor.length() > maxlen) { 228 | strColor = strColor.substring(0, maxlen); 229 | } 230 | int intColor = Integer.parseInt(strColor, 16); 231 | this.setContentValueAsInt(Calendars.CALENDAR_COLOR, intColor); 232 | } 233 | } 234 | 235 | /** 236 | * example 12345 237 | */ 238 | public int getCalendarColor() { 239 | return this.getContentValueAsInt(Calendars.CALENDAR_COLOR); 240 | } 241 | 242 | /** 243 | * example 12345 244 | */ 245 | public void setCalendarColor(int color) { 246 | this.setContentValueAsInt(Calendars.CALENDAR_COLOR, color); 247 | } 248 | 249 | /** 250 | * example: 251 | * should be: calendarname 252 | * but is: http://caldav.example.com/calendarserver.php/calendars/username/calendarname/ 253 | */ 254 | public String getCalendarName() { 255 | return this.getContentValueAsString(Calendars.NAME); 256 | } 257 | 258 | /** 259 | * example: 260 | * should be: calendarname 261 | * but is: http://caldav.example.com/calendarserver.php/calendars/username/calendarname/ 262 | */ 263 | public void setCalendarName(String calendarName) { 264 | this.setContentValueAsString(Calendars.NAME, calendarName); 265 | } 266 | 267 | /** 268 | * example: 8 269 | */ 270 | public int getAndroidCalendarId() { 271 | return this.getContentValueAsInt(Calendars._ID); 272 | } 273 | 274 | /** 275 | * example: 8 276 | */ 277 | public void setAndroidCalendarId(int androidCalendarId) { 278 | this.setContentValueAsInt(Calendars._ID, androidCalendarId); 279 | } 280 | 281 | /** 282 | * example: content://com.android.calendar/calendars/8 283 | */ 284 | public Uri getAndroidCalendarUri() { 285 | return ContentUris.withAppendedId(Calendars.CONTENT_URI, this.getAndroidCalendarId()); 286 | } 287 | 288 | /** 289 | * checks a given list of android calendars for a specific android calendar. 290 | * this calendar should be a server calendar as it is searched for. 291 | * if the calendar is not found, it will be created. 292 | * 293 | * @param androidCalList the list of android calendars 294 | * @return the found android calendar or null of fails 295 | */ 296 | public Uri checkAndroidCalendarList(CalendarList androidCalList, 297 | android.content.Context context) throws RemoteException { 298 | Uri androidCalendarUri = null; 299 | boolean isCalendarExist = false; 300 | 301 | DavCalendar androidCalendar = androidCalList.getCalendarByURI(this.getURI()); 302 | if (androidCalendar != null) { 303 | isCalendarExist = true; 304 | androidCalendar.foundServerSide = true; 305 | } 306 | 307 | if (!isCalendarExist) { 308 | DavCalendar newCal = this 309 | .createNewAndroidCalendar(this, androidCalList.getCalendarList() 310 | .size(), context); 311 | if (newCal != null) { 312 | androidCalList.addCalendar(newCal); 313 | androidCalendarUri = newCal.getAndroidCalendarUri(); 314 | } 315 | } else { 316 | androidCalendarUri = androidCalendar.getAndroidCalendarUri(); 317 | if (!this.getCalendarColorAsString().equals("")) { 318 | this.updateAndroidCalendar(androidCalendarUri, Calendars.CALENDAR_COLOR, 319 | getColorAsHex(this.getCalendarColorAsString())); 320 | } 321 | if ((this.ContentValues.containsKey(Calendars.CALENDAR_DISPLAY_NAME)) && 322 | (androidCalendar.ContentValues.containsKey(Calendars.CALENDAR_DISPLAY_NAME))) { 323 | String serverDisplayName = this.ContentValues 324 | .getAsString(Calendars.CALENDAR_DISPLAY_NAME); 325 | String clientDisplayName = androidCalendar.ContentValues 326 | .getAsString(Calendars.CALENDAR_DISPLAY_NAME); 327 | if (!serverDisplayName.equals(clientDisplayName)) { 328 | this.updateAndroidCalendar(androidCalendarUri, Calendars.CALENDAR_DISPLAY_NAME, 329 | serverDisplayName); 330 | } 331 | } 332 | } 333 | 334 | return androidCalendarUri; 335 | } 336 | 337 | /** 338 | * COMPAT: the calendar Uri was stored as calendar Name. this function updates the URI 339 | * (_SYNC_ID) 340 | * 341 | * @param calendarUri the real calendarUri 342 | * @return success of this function 343 | */ 344 | private boolean correctSyncID(String calendarUri) { 345 | boolean lcResult = false; 346 | Log.v(TAG, "correcting SyncID for calendar:" + this 347 | .getContentValueAsString(Calendars.CALENDAR_DISPLAY_NAME)); 348 | 349 | ContentValues mUpdateValues = new ContentValues(); 350 | mUpdateValues.put(DavCalendar.URI, calendarUri); 351 | 352 | try { 353 | mProvider.update(this.SyncAdapterCalendar(), mUpdateValues, null, null); 354 | lcResult = true; 355 | } catch (RemoteException e) { 356 | Log.e(getcTag(), e.getMessage()); 357 | } 358 | 359 | return lcResult; 360 | } 361 | 362 | /** 363 | * COMPAT: the serverurl (CAL_SYNC2) was not sored within a calendar. this fixes it. (see #98) 364 | * 365 | * @param serverUrl the current serverurl 366 | * @return success of this function 367 | */ 368 | private boolean correctServerUrl(String serverUrl) { 369 | boolean lcResult = false; 370 | Log.v(TAG, "correcting ServerUrl for calendar:" + this 371 | .getContentValueAsString(Calendars.CALENDAR_DISPLAY_NAME)); 372 | 373 | ContentValues mUpdateValues = new ContentValues(); 374 | mUpdateValues.put(DavCalendar.SERVERURL, serverUrl); 375 | 376 | try { 377 | mProvider.update(this.SyncAdapterCalendar(), mUpdateValues, null, null); 378 | lcResult = true; 379 | } catch (RemoteException e) { 380 | Log.e(getcTag(), e.getMessage()); 381 | } 382 | 383 | return lcResult; 384 | } 385 | 386 | /** 387 | * creates a new androidCalendar 388 | * 389 | * @return the new androidCalendar or null if fails 390 | */ 391 | private DavCalendar createNewAndroidCalendar(DavCalendar serverCalendar, int index, 392 | android.content.Context context) { 393 | Uri newUri = null; 394 | DavCalendar lcResult = null; 395 | 396 | final ContentValues contentValues = new ContentValues(); 397 | contentValues.put(DavCalendar.URI, serverCalendar.getURI().toString()); 398 | contentValues.put(DavCalendar.SERVERURL, this.ServerUrl); 399 | 400 | contentValues.put(Calendars.VISIBLE, 1); 401 | contentValues.put(Calendars.CALENDAR_DISPLAY_NAME, serverCalendar.getCalendarDisplayName()); 402 | contentValues.put(Calendars.ACCOUNT_NAME, mAccount.name); 403 | contentValues.put(Calendars.ACCOUNT_TYPE, mAccount.type); 404 | contentValues.put(Calendars.OWNER_ACCOUNT, mAccount.name); 405 | contentValues.put(Calendars.SYNC_EVENTS, 1); 406 | contentValues.put(Calendars.CALENDAR_ACCESS_LEVEL, Calendars.CAL_ACCESS_OWNER); 407 | 408 | String calendarColorAsString = serverCalendar.getCalendarColorAsString(); 409 | if (!calendarColorAsString.isEmpty()) { 410 | int color = getColorAsHex(calendarColorAsString); 411 | contentValues.put(Calendars.CALENDAR_COLOR, color); 412 | } else { 413 | // find a color 414 | index = index % CalendarColors.colors.length; 415 | contentValues.put(Calendars.CALENDAR_COLOR, CalendarColors.colors[2]); 416 | } 417 | 418 | try { 419 | newUri = mProvider 420 | .insert(asSyncAdapter(Calendars.CONTENT_URI, mAccount.name, mAccount.type), 421 | contentValues); 422 | } catch (RemoteException e) { 423 | e.printStackTrace(); 424 | } 425 | 426 | // it is possible that this calendar already exists but the provider failed to find it within isCalendarExist() 427 | // the adapter would try to create a new calendar but the provider fails again to create a new calendar. 428 | if (newUri != null) { 429 | long newCalendarId = ContentUris.parseId(newUri); 430 | 431 | Cursor cur = null; 432 | Uri uri = Calendars.CONTENT_URI; 433 | String selection = "(" + Calendars._ID + " = ?)"; 434 | String[] selectionArgs = new String[]{String.valueOf(newCalendarId)}; 435 | 436 | // Submit the query and get a Cursor object back. 437 | try { 438 | cur = mProvider.query(uri, null, selection, selectionArgs, null); 439 | } catch (RemoteException e) { 440 | e.printStackTrace(); 441 | } 442 | 443 | if (cur != null) { 444 | while (cur.moveToNext()) { 445 | lcResult = new DavCalendar(mAccount, mProvider, cur, this.Source, this.ServerUrl); 446 | lcResult.foundServerSide = true; 447 | } 448 | cur.close(); 449 | } 450 | if (lcResult != null) { 451 | Log.i(TAG, "New calendar created : URI=" + lcResult.getAndroidCalendarUri()); 452 | NotificationsHelper.signalSyncErrors(context, "CalDAV Sync Adapter", 453 | "new calendar found: " + lcResult 454 | .getCalendarDisplayName()); 455 | mNotifyList.add(lcResult.getAndroidCalendarUri()); 456 | } 457 | } 458 | 459 | return lcResult; 460 | } 461 | 462 | private int getColorAsHex(String calendarColorAsString) { 463 | int color = 0x0000FF00; 464 | Pattern p = Pattern.compile("#?(\\p{XDigit}{6})(\\p{XDigit}{2})?"); 465 | Matcher m = p.matcher(calendarColorAsString); 466 | if (m.find()) { 467 | int color_rgb = Integer.parseInt(m.group(1), 16); 468 | int color_alpha = m.group(2) != null ? (Integer.parseInt(m.group(2), 16) & 0xFF) : 0xFF; 469 | color = (color_alpha << 24) | color_rgb; 470 | } 471 | return color; 472 | } 473 | 474 | /** 475 | * there is no corresponding calendar on server side. time to delete this calendar on android 476 | * side. 477 | */ 478 | public boolean deleteAndroidCalendar() { 479 | boolean lcResult = false; 480 | 481 | String mSelectionClause = "(" + Calendars._ID + " = ?)"; 482 | int calendarId = this.getAndroidCalendarId(); 483 | String[] mSelectionArgs = {Long.toString(calendarId)}; 484 | 485 | int lcCountDeleted = 0; 486 | try { 487 | lcCountDeleted = mProvider.delete(this.SyncAdapter(), mSelectionClause, mSelectionArgs); 488 | Log.i(TAG, "Calendar deleted: " + String.valueOf(calendarId)); 489 | this.mNotifyList.add(this.getAndroidCalendarUri()); 490 | lcResult = true; 491 | } catch (RemoteException e) { 492 | Log.e(getcTag(),e.getMessage()); 493 | } 494 | Log.d(TAG, "Android Calendars deleted: " + Integer.toString(lcCountDeleted)); 495 | 496 | return lcResult; 497 | } 498 | 499 | /** 500 | * updates the android calendar 501 | * 502 | * @param calendarUri the uri of the androidCalendar 503 | * @param target must be from android.provider.CalendarContract.Calendars 504 | * @param value the new value for the target 505 | */ 506 | private void updateAndroidCalendar(Uri calendarUri, String target, int value) 507 | throws RemoteException { 508 | ContentValues mUpdateValues = new ContentValues(); 509 | mUpdateValues.put(target, value); 510 | 511 | mProvider.update(asSyncAdapter(calendarUri, mAccount.name, mAccount.type), mUpdateValues, 512 | null, null); 513 | } 514 | 515 | /** 516 | * updates the android calendar 517 | * 518 | * @param calendarUri the uri of the androidCalendar 519 | * @param target must be from android.provider.CalendarContract.Calendars 520 | * @param value the new value for the target 521 | */ 522 | private void updateAndroidCalendar(Uri calendarUri, String target, String value) 523 | throws RemoteException { 524 | ContentValues mUpdateValues = new ContentValues(); 525 | mUpdateValues.put(target, value); 526 | 527 | mProvider.update(asSyncAdapter(calendarUri, mAccount.name, mAccount.type), mUpdateValues, 528 | null, null); 529 | } 530 | 531 | /** 532 | * marks the android event as already handled 533 | */ 534 | public boolean tagAndroidEvent(AndroidEvent androidEvent) throws RemoteException { 535 | boolean lcResult = false; 536 | 537 | ContentValues values = new ContentValues(); 538 | values.put(Event.INTERNALTAG, mTagCounter); 539 | 540 | int lcRowCount = this.mProvider 541 | .update(asSyncAdapter(androidEvent.getUri(), this.mAccount.name, 542 | this.mAccount.type), values, null, null); 543 | 544 | if (lcRowCount == 1) { 545 | lcResult = true; 546 | mTagCounter += 1; 547 | } else { 548 | Log.v(TAG, "EVENT NOT TAGGED!"); 549 | } 550 | 551 | return lcResult; 552 | } 553 | 554 | /** 555 | * removes the tag of all android events 556 | */ 557 | public int untagAndroidEvents() throws RemoteException { 558 | int lcRowCount = 0; 559 | int lcSteps = 100; 560 | ContentValues values = new ContentValues(); 561 | values.put(Event.INTERNALTAG, 0); 562 | 563 | for (int i = 1; i < this.mTagCounter; i = i + lcSteps) { 564 | String mSelectionClause = "(CAST(" + Event.INTERNALTAG + " AS INT) >= ?) AND (CAST(" 565 | + Event.INTERNALTAG + " AS INT) < ?) AND (" + Events.CALENDAR_ID + " = ?)"; 566 | String[] mSelectionArgs = {String.valueOf(i), String.valueOf(i + lcSteps), 567 | Long.toString(ContentUris 568 | .parseId(this.getAndroidCalendarUri()))}; 569 | lcRowCount += this.mProvider.update(asSyncAdapter(Events.CONTENT_URI, this.mAccount.name, 570 | this.mAccount.type), values, mSelectionClause, mSelectionArgs); 571 | } 572 | return lcRowCount; 573 | } 574 | 575 | /** 576 | * Events not being tagged are for deletion 577 | */ 578 | public int deleteUntaggedEvents() throws RemoteException { 579 | String mSelectionClause = "(" + Event.INTERNALTAG + " < ?) AND (" + Events.CALENDAR_ID 580 | + " = ?)"; 581 | String[] mSelectionArgs = {"1", 582 | Long.toString(ContentUris.parseId(this.getAndroidCalendarUri()))}; 583 | 584 | int lcCountDeleted; 585 | lcCountDeleted = this.mProvider 586 | .delete(asSyncAdapter(Events.CONTENT_URI, this.mAccount.name, this.mAccount.type), 587 | mSelectionClause, mSelectionArgs); 588 | 589 | return lcCountDeleted; 590 | } 591 | 592 | private Uri SyncAdapterCalendar() { 593 | return asSyncAdapter(this.getAndroidCalendarUri(), mAccount.name, mAccount.type); 594 | } 595 | 596 | private Uri SyncAdapter() { 597 | return asSyncAdapter(Calendars.CONTENT_URI, mAccount.name, mAccount.type); 598 | } 599 | 600 | public void setAccount(Account account) { 601 | this.mAccount = account; 602 | } 603 | 604 | public void setProvider(ContentProviderClient provider) { 605 | this.mProvider = provider; 606 | } 607 | 608 | /** 609 | * general access function to ContentValues 610 | * 611 | * @param Item the item name from Calendars.* 612 | * @return the value for the item 613 | */ 614 | private String getContentValueAsString(String Item) { 615 | String lcResult = ""; 616 | if (this.ContentValues.containsKey(Item)) { 617 | lcResult = this.ContentValues.getAsString(Item); 618 | } 619 | return lcResult; 620 | } 621 | 622 | /** 623 | * general access function to ContentValues 624 | * 625 | * @param Item the item name from Calendars.* 626 | * @return the value for the item 627 | */ 628 | private int getContentValueAsInt(String Item) { 629 | int lcResult = 0; 630 | if (this.ContentValues.containsKey(Item)) { 631 | lcResult = this.ContentValues.getAsInteger(Item); 632 | } 633 | return lcResult; 634 | } 635 | 636 | /** 637 | * general access function to ContentValues 638 | * 639 | * @param Item the item name from Calendars.* 640 | * @param Value the value for the item 641 | * @return success of this function 642 | */ 643 | private boolean setContentValueAsString(String Item, String Value) { 644 | boolean lcResult = false; 645 | 646 | if (this.ContentValues.containsKey(Item)) { 647 | this.ContentValues.remove(Item); 648 | } 649 | this.ContentValues.put(Item, Value); 650 | 651 | return lcResult; 652 | } 653 | 654 | /** 655 | * general access function to ContentValues 656 | * 657 | * @param Item the item name from Calendars.* 658 | * @param Value the value for the item 659 | * @return success of this function 660 | */ 661 | private boolean setContentValueAsInt(String Item, int Value) { 662 | boolean lcResult = false; 663 | 664 | if (this.ContentValues.containsKey(Item)) { 665 | this.ContentValues.remove(Item); 666 | } 667 | this.ContentValues.put(Item, Value); 668 | 669 | return lcResult; 670 | } 671 | 672 | public ArrayList getNotifyList() { 673 | return this.mNotifyList; 674 | } 675 | 676 | public ArrayList getCalendarEvents() { 677 | return this.mCalendarEvents; 678 | } 679 | 680 | public boolean readCalendarEvents(CaldavFacade facade) { 681 | boolean lcResult = false; 682 | 683 | try { 684 | this.mCalendarEvents = facade.getCalendarEvents(this); 685 | lcResult = true; 686 | } catch (ClientProtocolException e) { 687 | Log.e(getcTag(),e.getMessage()); 688 | lcResult = false; 689 | } catch (URISyntaxException e) { 690 | Log.e(getcTag(),e.getMessage()); 691 | lcResult = false; 692 | } catch (IOException e) { 693 | Log.e(getcTag(),e.getMessage()); 694 | lcResult = false; 695 | } catch (ParserConfigurationException e) { 696 | Log.e(getcTag(),e.getMessage()); 697 | lcResult = false; 698 | } catch (SAXException e) { 699 | Log.e(getcTag(),e.getMessage()); 700 | lcResult = false; 701 | } 702 | 703 | return lcResult; 704 | } 705 | 706 | public enum CalendarSource { 707 | undefined, Android, CalDAV 708 | } 709 | 710 | } 711 | -------------------------------------------------------------------------------- /ACalDAV/src/org/gege/caldavsyncadapter/caldav/http/HttpDelete.java: -------------------------------------------------------------------------------- 1 | package org.gege.caldavsyncadapter.caldav.http; 2 | 3 | import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; 4 | import org.apache.http.client.methods.HttpUriRequest; 5 | 6 | public class HttpDelete extends HttpEntityEnclosingRequestBase implements HttpUriRequest { 7 | 8 | @Override 9 | public String getMethod() { 10 | return "DELETE"; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ACalDAV/src/org/gege/caldavsyncadapter/caldav/http/HttpPropFind.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Gerald Garcia 3 | * 4 | * This file is part of Andoid Caldav Sync Adapter Free. 5 | * 6 | * Andoid Caldav Sync Adapter Free is free software: you can redistribute 7 | * it and/or modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation, either version 3 of the 9 | * License, or at your option any later version. 10 | * 11 | * Andoid Caldav Sync Adapter Free is distributed in the hope that 12 | * it will be useful, but WITHOUT ANY WARRANTY; without even the implied 13 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with Andoid Caldav Sync Adapter Free. 18 | * If not, see . 19 | * 20 | */ 21 | 22 | package org.gege.caldavsyncadapter.caldav.http; 23 | 24 | import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; 25 | import org.apache.http.client.methods.HttpUriRequest; 26 | 27 | public class HttpPropFind extends HttpEntityEnclosingRequestBase implements HttpUriRequest { 28 | 29 | @Override 30 | public String getMethod() { 31 | return "PROPFIND"; 32 | } 33 | 34 | 35 | } 36 | -------------------------------------------------------------------------------- /ACalDAV/src/org/gege/caldavsyncadapter/caldav/http/HttpPut.java: -------------------------------------------------------------------------------- 1 | package org.gege.caldavsyncadapter.caldav.http; 2 | 3 | import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; 4 | import org.apache.http.client.methods.HttpUriRequest; 5 | 6 | public class HttpPut extends HttpEntityEnclosingRequestBase implements HttpUriRequest { 7 | 8 | @Override 9 | public String getMethod() { 10 | return "PUT"; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ACalDAV/src/org/gege/caldavsyncadapter/caldav/http/HttpReport.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Gerald Garcia 3 | * 4 | * This file is part of Andoid Caldav Sync Adapter Free. 5 | * 6 | * Andoid Caldav Sync Adapter Free is free software: you can redistribute 7 | * it and/or modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation, either version 3 of the 9 | * License, or at your option any later version. 10 | * 11 | * Andoid Caldav Sync Adapter Free is distributed in the hope that 12 | * it will be useful, but WITHOUT ANY WARRANTY; without even the implied 13 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with Andoid Caldav Sync Adapter Free. 18 | * If not, see . 19 | * 20 | */ 21 | 22 | package org.gege.caldavsyncadapter.caldav.http; 23 | 24 | import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; 25 | import org.apache.http.client.methods.HttpUriRequest; 26 | 27 | public class HttpReport extends HttpEntityEnclosingRequestBase implements HttpUriRequest { 28 | 29 | public static final String USER_DATA_TRUST_ALL_KEY = "USER_DATA_TRUSTALL_KEY"; 30 | 31 | @Override 32 | public String getMethod() { 33 | return "REPORT"; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /ACalDAV/src/org/gege/caldavsyncadapter/caldav/xml/CalendarHomeHandler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, David Wiesner 3 | * 4 | * This file is part of Andoid Caldav Sync Adapter Free. 5 | * 6 | * Andoid Caldav Sync Adapter Free is free software: you can redistribute 7 | * it and/or modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation, either version 3 of the 9 | * License, or at your option any later version. 10 | * 11 | * Andoid Caldav Sync Adapter Free is distributed in the hope that 12 | * it will be useful, but WITHOUT ANY WARRANTY; without even the implied 13 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with Andoid Caldav Sync Adapter Free. 18 | * If not, see . 19 | * 20 | */ 21 | 22 | package org.gege.caldavsyncadapter.caldav.xml; 23 | 24 | import android.util.Log; 25 | 26 | import org.xml.sax.Attributes; 27 | import org.xml.sax.SAXException; 28 | import org.xml.sax.helpers.DefaultHandler; 29 | 30 | import java.net.URI; 31 | import java.net.URISyntaxException; 32 | import java.util.ArrayList; 33 | import java.util.List; 34 | 35 | import de.we.acaldav.BuildConfig; 36 | 37 | public class CalendarHomeHandler extends DefaultHandler { 38 | 39 | private static final String HREF = "href"; 40 | 41 | private static final String CALENDAR_HOME_SET = "calendar-home-set"; 42 | 43 | public List calendarHomeSet = new ArrayList(); 44 | 45 | private boolean isInCalendarHomeSet = false; 46 | 47 | private StringBuilder stringBuilder = new StringBuilder(); 48 | 49 | private String currentElement; 50 | 51 | private URI principalURI; 52 | 53 | public CalendarHomeHandler(URI principalURI) { 54 | this.principalURI = principalURI; 55 | } 56 | 57 | @Override 58 | public void startElement(String uri, String localName, String qName, 59 | Attributes attributes) throws SAXException { 60 | if (CALENDAR_HOME_SET.equals(localName)) { 61 | isInCalendarHomeSet = true; 62 | } 63 | currentElement = localName; 64 | stringBuilder.setLength(0); 65 | } 66 | 67 | @Override 68 | public void characters(char[] ch, int start, int length) 69 | throws SAXException { 70 | if (HREF.equals(currentElement) && isInCalendarHomeSet) { 71 | stringBuilder.append(ch, start, length); 72 | } 73 | } 74 | 75 | @Override 76 | public void endElement(String uri, String localName, String qName) 77 | throws SAXException { 78 | if (HREF.equals(localName) && isInCalendarHomeSet) { 79 | String calendarHomeSet = stringBuilder.toString(); 80 | try { 81 | URI calendarHomeSetURI = new URI(calendarHomeSet); 82 | calendarHomeSetURI = principalURI.resolve(calendarHomeSetURI); 83 | this.calendarHomeSet.add(calendarHomeSetURI); 84 | } catch (URISyntaxException e) { 85 | if (BuildConfig.DEBUG) { 86 | Log.e(CalendarHomeHandler.class.getSimpleName(), 87 | "uri malformed: " + calendarHomeSet); 88 | } else { 89 | Log.e(CalendarHomeHandler.class.getSimpleName(), 90 | "uri malformed in calendar-home-set/href"); 91 | } 92 | } 93 | } 94 | if (CALENDAR_HOME_SET.equals(localName)) { 95 | isInCalendarHomeSet = false; 96 | } 97 | currentElement = null; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /ACalDAV/src/org/gege/caldavsyncadapter/caldav/xml/CalendarsHandler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, David Wiesner 3 | * 4 | * This file is part of Andoid Caldav Sync Adapter Free. 5 | * 6 | * Andoid Caldav Sync Adapter Free is free software: you can redistribute 7 | * it and/or modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation, either version 3 of the 9 | * License, or at your option any later version. 10 | * 11 | * Andoid Caldav Sync Adapter Free is distributed in the hope that 12 | * it will be useful, but WITHOUT ANY WARRANTY; without even the implied 13 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with Andoid Caldav Sync Adapter Free. 18 | * If not, see . 19 | * 20 | */ 21 | 22 | package org.gege.caldavsyncadapter.caldav.xml; 23 | 24 | import android.util.Log; 25 | 26 | import org.gege.caldavsyncadapter.caldav.entities.DavCalendar; 27 | import org.gege.caldavsyncadapter.caldav.entities.DavCalendar.CalendarSource; 28 | import org.xml.sax.Attributes; 29 | import org.xml.sax.SAXException; 30 | import org.xml.sax.helpers.DefaultHandler; 31 | 32 | import java.net.URI; 33 | import java.net.URISyntaxException; 34 | import java.util.ArrayList; 35 | import java.util.Arrays; 36 | import java.util.List; 37 | 38 | import de.we.acaldav.BuildConfig; 39 | 40 | public class CalendarsHandler extends DefaultHandler { 41 | 42 | private static final String CALENDAR = "calendar"; 43 | 44 | private static final String RESOURCETYPE = "resourcetype"; 45 | 46 | private static final String CALENDAR_COLOR = "calendar-color"; 47 | 48 | private static final String GETCTAG = "getctag"; 49 | 50 | private static final String DISPLAYNAME = "displayname"; 51 | 52 | private static final String RESPONSE = "response"; 53 | 54 | private static final String HREF = "href"; 55 | 56 | public final static List TAGS = Arrays.asList(HREF, RESOURCETYPE, 57 | DISPLAYNAME, GETCTAG, CALENDAR_COLOR); 58 | 59 | public List calendars = new ArrayList(); 60 | 61 | private URI homeURI; 62 | 63 | private StringBuilder stringBuilder = new StringBuilder(); 64 | 65 | private String currentElement; 66 | 67 | private DavCalendar calendar; 68 | 69 | private boolean isInResourceType = false; 70 | 71 | private boolean isCalendarResource; 72 | 73 | public CalendarsHandler(URI homeURI) { 74 | this.homeURI = homeURI; 75 | } 76 | 77 | @Override 78 | public void startElement(String uri, String localName, String qName, 79 | Attributes attributes) throws SAXException { 80 | if (RESPONSE.equals(localName)) { 81 | calendar = new DavCalendar(CalendarSource.CalDAV); 82 | isCalendarResource = false; 83 | } else if (RESOURCETYPE.equals(localName)) { 84 | isInResourceType = true; 85 | } else if (isInResourceType && CALENDAR.equals(localName)) { 86 | isCalendarResource = true; 87 | } 88 | currentElement = localName; 89 | stringBuilder.setLength(0); 90 | } 91 | 92 | @Override 93 | public void characters(char[] ch, int start, int length) 94 | throws SAXException { 95 | if (TAGS.contains(currentElement)) { 96 | stringBuilder.append(ch, start, length); 97 | } 98 | } 99 | 100 | @Override 101 | public void endElement(String uri, String localName, String qName) 102 | throws SAXException { 103 | if (TAGS.contains(localName)) { 104 | if (calendar != null) { 105 | if (HREF.equals(localName)) { 106 | String calendarUrl = stringBuilder.toString(); 107 | calendarUrl = calendarUrl.trim(); 108 | try { 109 | URI calendarURI = new URI(calendarUrl); 110 | calendar.setURI(homeURI.resolve(calendarURI)); 111 | } catch (URISyntaxException e) { 112 | if (BuildConfig.DEBUG) { 113 | Log.e(CalendarsHandler.class.getSimpleName(), 114 | "calendar-uri malformed: " + calendarUrl); 115 | } else { 116 | Log.e(CalendarsHandler.class.getSimpleName(), 117 | "uri malformed in href"); 118 | } 119 | } 120 | } else if (DISPLAYNAME.equals(localName)) { 121 | calendar.setCalendarDisplayName(stringBuilder.toString()); 122 | } else if (GETCTAG.equals(localName)) { 123 | calendar.setCTag(stringBuilder.toString(), false); 124 | } else if (CALENDAR_COLOR.equals(localName)) { 125 | calendar.setCalendarColorAsString(stringBuilder.toString()); 126 | } 127 | } 128 | } else if (RESPONSE.equals(localName)) { 129 | if (isCalendarResource && isValidCalendar(calendar)) { 130 | calendars.add(calendar); 131 | } 132 | } 133 | currentElement = null; 134 | } 135 | 136 | private boolean isValidCalendar(DavCalendar calendar) { 137 | return calendar != null && calendar.getURI() != null 138 | && calendar.getcTag() != null 139 | && calendar.getCalendarDisplayName() != null; 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /ACalDAV/src/org/gege/caldavsyncadapter/caldav/xml/MultiStatusHandler.java: -------------------------------------------------------------------------------- 1 | package org.gege.caldavsyncadapter.caldav.xml; 2 | 3 | import org.gege.caldavsyncadapter.caldav.xml.sax.MultiStatus; 4 | import org.gege.caldavsyncadapter.caldav.xml.sax.Prop; 5 | import org.gege.caldavsyncadapter.caldav.xml.sax.PropStat; 6 | import org.gege.caldavsyncadapter.caldav.xml.sax.Response; 7 | import org.xml.sax.Attributes; 8 | import org.xml.sax.SAXException; 9 | import org.xml.sax.helpers.DefaultHandler; 10 | 11 | 12 | public class MultiStatusHandler extends DefaultHandler { 13 | 14 | public MultiStatus mMultiStatus; 15 | 16 | private Response mResponse; 17 | 18 | private PropStat mPropStat; 19 | 20 | private Prop mProp; 21 | 22 | private String mCurrentValue; 23 | 24 | private String RESPONSE = "response"; 25 | 26 | private String HREF = "href"; 27 | 28 | private String PROPSTAT = "propstat"; 29 | 30 | private String PROP = "prop"; 31 | 32 | private String STATUS = "status"; 33 | 34 | private String CALENDARDATA = "calendar-data"; 35 | 36 | private String GETETAG = "getetag"; 37 | 38 | public MultiStatusHandler() { 39 | mMultiStatus = new MultiStatus(); 40 | } 41 | 42 | @Override 43 | public void characters(char[] ch, int start, int length) throws SAXException { 44 | mCurrentValue += new String(ch, start, length); 45 | } 46 | 47 | @Override 48 | public void startElement(String uri, String localName, String qName, Attributes atts) 49 | throws SAXException { 50 | mCurrentValue = ""; 51 | if (localName.equals(RESPONSE)) { 52 | mResponse = new Response(); 53 | mMultiStatus.responseList.add(mResponse); 54 | } else if (localName.equals(PROPSTAT)) { 55 | mPropStat = new PropStat(); 56 | mResponse.propstat = mPropStat; 57 | } else if (localName.equals(PROP)) { 58 | mProp = new Prop(); 59 | mPropStat.prop = mProp; 60 | } 61 | } 62 | 63 | @Override 64 | public void endElement(String uri, String localName, String qName) throws SAXException { 65 | if (localName.equals(HREF)) { 66 | mResponse.href = mCurrentValue; 67 | } else if (localName.equals(STATUS)) { 68 | if (mPropStat != null) { 69 | mPropStat.status = mCurrentValue; 70 | } 71 | } else if (localName.equals(CALENDARDATA)) { 72 | mProp.calendardata = mCurrentValue; 73 | } else if (localName.equals(GETETAG)) { 74 | mProp.getetag = mCurrentValue; 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /ACalDAV/src/org/gege/caldavsyncadapter/caldav/xml/ServerInfoHandler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, David Wiesner 3 | * 4 | * This file is part of Andoid Caldav Sync Adapter Free. 5 | * 6 | * Andoid Caldav Sync Adapter Free is free software: you can redistribute 7 | * it and/or modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation, either version 3 of the 9 | * License, or at your option any later version. 10 | * 11 | * Andoid Caldav Sync Adapter Free is distributed in the hope that 12 | * it will be useful, but WITHOUT ANY WARRANTY; without even the implied 13 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with Andoid Caldav Sync Adapter Free. 18 | * If not, see . 19 | * 20 | */ 21 | 22 | package org.gege.caldavsyncadapter.caldav.xml; 23 | 24 | import org.xml.sax.Attributes; 25 | import org.xml.sax.SAXException; 26 | import org.xml.sax.helpers.DefaultHandler; 27 | 28 | import java.util.Arrays; 29 | import java.util.List; 30 | 31 | public class ServerInfoHandler extends DefaultHandler { 32 | 33 | private static final String HREF = "href"; 34 | 35 | private static final String PRINCIPAL_URL = "principal-URL"; 36 | 37 | private static final String CURRENT_USER_PRINCIPAL = "current-user-principal"; 38 | 39 | private final static List TAGS = Arrays.asList( 40 | CURRENT_USER_PRINCIPAL, PRINCIPAL_URL); 41 | 42 | public String currentUserPrincipal = null; 43 | 44 | public String principalUrl = null; 45 | 46 | private StringBuilder stringBuilder = new StringBuilder(); 47 | 48 | private String inParentElement; 49 | 50 | private String currentElement; 51 | 52 | @Override 53 | public void startElement(String uri, String localName, String qName, 54 | Attributes attributes) throws SAXException { 55 | if (TAGS.contains(localName)) { 56 | inParentElement = localName; 57 | } 58 | currentElement = localName; 59 | stringBuilder.setLength(0); 60 | } 61 | 62 | @Override 63 | public void characters(char[] ch, int start, int length) 64 | throws SAXException { 65 | if (HREF.equals(currentElement) && TAGS.contains(inParentElement)) { 66 | stringBuilder.append(ch, start, length); 67 | } 68 | } 69 | 70 | @Override 71 | public void endElement(String uri, String localName, String qName) 72 | throws SAXException { 73 | if (HREF.equals(currentElement) && TAGS.contains(inParentElement)) { 74 | if (CURRENT_USER_PRINCIPAL.equals(inParentElement)) { 75 | currentUserPrincipal = stringBuilder.toString(); 76 | } else { 77 | principalUrl = stringBuilder.toString(); 78 | } 79 | } 80 | if (TAGS.contains(localName)) { 81 | inParentElement = null; 82 | } 83 | currentElement = null; 84 | 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /ACalDAV/src/org/gege/caldavsyncadapter/caldav/xml/sax/MultiStatus.java: -------------------------------------------------------------------------------- 1 | package org.gege.caldavsyncadapter.caldav.xml.sax; 2 | 3 | import java.util.ArrayList; 4 | 5 | public class MultiStatus { 6 | 7 | public ArrayList responseList = new ArrayList(); 8 | } 9 | -------------------------------------------------------------------------------- /ACalDAV/src/org/gege/caldavsyncadapter/caldav/xml/sax/Prop.java: -------------------------------------------------------------------------------- 1 | package org.gege.caldavsyncadapter.caldav.xml.sax; 2 | 3 | public class Prop { 4 | 5 | public String calendardata = ""; 6 | 7 | public String getetag = ""; 8 | } 9 | -------------------------------------------------------------------------------- /ACalDAV/src/org/gege/caldavsyncadapter/caldav/xml/sax/PropStat.java: -------------------------------------------------------------------------------- 1 | package org.gege.caldavsyncadapter.caldav.xml.sax; 2 | 3 | public class PropStat { 4 | 5 | public Prop prop; 6 | 7 | public String status = ""; 8 | } 9 | -------------------------------------------------------------------------------- /ACalDAV/src/org/gege/caldavsyncadapter/caldav/xml/sax/Response.java: -------------------------------------------------------------------------------- 1 | package org.gege.caldavsyncadapter.caldav.xml.sax; 2 | 3 | public class Response { 4 | 5 | public String href = ""; 6 | 7 | public PropStat propstat; 8 | } 9 | -------------------------------------------------------------------------------- /ACalDAV/src/org/gege/caldavsyncadapter/syncadapter/SyncService.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, David Wiesner 3 | * 4 | * This file is part of Andoid Caldav Sync Adapter Free. 5 | * 6 | * Andoid Caldav Sync Adapter Free is free software: you can redistribute 7 | * it and/or modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation, either version 3 of the 9 | * License, or at your option any later version. 10 | * 11 | * Andoid Caldav Sync Adapter Free is distributed in the hope that 12 | * it will be useful, but WITHOUT ANY WARRANTY; without even the implied 13 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with Andoid Caldav Sync Adapter Free. 18 | * If not, see . 19 | * 20 | */ 21 | 22 | package org.gege.caldavsyncadapter.syncadapter; 23 | 24 | import android.app.Service; 25 | import android.content.Intent; 26 | import android.os.IBinder; 27 | 28 | import de.we.acaldav.App; 29 | 30 | public class SyncService extends Service { 31 | 32 | private static final Object sSyncAdapterLock = new Object(); 33 | 34 | private static SyncAdapter sSyncAdapter = null; 35 | 36 | @Override 37 | public void onCreate() { 38 | synchronized (sSyncAdapterLock) { 39 | if (sSyncAdapter == null) { 40 | sSyncAdapter = new SyncAdapter(getApplicationContext(), true); 41 | } 42 | App.setContext(getApplicationContext()); 43 | } 44 | } 45 | 46 | @Override 47 | public IBinder onBind(Intent intent) { 48 | return sSyncAdapter.getSyncAdapterBinder(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /ACalDAV/src/org/gege/caldavsyncadapter/syncadapter/notifications/NotificationsHelper.java: -------------------------------------------------------------------------------- 1 | package org.gege.caldavsyncadapter.syncadapter.notifications; 2 | 3 | import android.app.NotificationManager; 4 | import android.content.Context; 5 | import android.support.v4.app.NotificationCompat; 6 | 7 | import de.we.acaldav.R; 8 | 9 | public class NotificationsHelper { 10 | 11 | 12 | public static void signalSyncErrors(Context context, String title, String text) { 13 | NotificationCompat.Builder mBuilder = 14 | new NotificationCompat.Builder(context) 15 | .setSmallIcon(R.drawable.icon) 16 | .setContentTitle(title) 17 | .setContentText(text); 18 | 19 | NotificationManager mNotificationManager = 20 | (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); 21 | 22 | // mId allows you to update the notification later on. 23 | int mId = 0; 24 | mNotificationManager.notify(mId, mBuilder.build()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Moved to Gitlab [ennswi/AndroidCaldavSyncAdapater](https://gitlab.com/ennswi/AndroidCaldavSyncAdapater.git) 2 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | buildscript { 3 | repositories { 4 | mavenCentral() 5 | } 6 | dependencies { 7 | classpath 'com.android.tools.build:gradle:1.5.0' 8 | } 9 | } 10 | 11 | allprojects { 12 | repositories { 13 | mavenCentral() 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /config/quality/checkstyle/checkstyle-suppressions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /config/quality/checkstyle/checkstyle.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | -------------------------------------------------------------------------------- /config/quality/checkstyle/checkstyle.xsl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 80 | 81 | CheckStyle Audit 82 | 83 | 84 | Designed for use with CheckStyle and Ant. 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | Files 115 | 116 | 117 | Name 118 | Errors 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | File 136 | 137 | 138 | 139 | Error Description 140 | Line 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | Back to top 151 | 152 | 153 | 154 | 155 | Summary 156 | 157 | 158 | 159 | 160 | Files 161 | Errors 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | a 174 | b 175 | 176 | 177 | 178 | 179 | -------------------------------------------------------------------------------- /config/quality/checkstyle/checkstyle_QA.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 17 | 18 | 19 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | -------------------------------------------------------------------------------- /config/quality/findbugs/findbugs-filter-exclude.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /config/quality/findbugs/findbugs-filter-include.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /config/quality/pmd/pmd-configuration.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | Ulli's PMD rules. 10 | 11 | 12 | .*/gen/.* 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /config/quality/pmd/rulesets/android.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | These rules deal with the Android SDK, mostly related to best practices. 9 | To get better results, make sure that the auxclasspath is defined for type resolution to work. 10 | 11 | 12 | 17 | Super should be called at the start of the method 18 | 3 19 | 20 | 21 | 40 | 41 | 42 | 43 | 51 | 52 | 53 | 54 | 59 | Super should be called at the end of the method 60 | 3 61 | 62 | 63 | 64 | 81 | 82 | 83 | 84 | 85 | 93 | 94 | 95 | 96 | 101 | Use Environment.getExternalStorageDirectory() instead of "/sdcard" 102 | 3 103 | 104 | 105 | //Literal[starts-with(@Image,'"/sdcard')] 106 | 107 | 108 | 109 | 118 | 119 | 120 | 121 | 122 | -------------------------------------------------------------------------------- /config/quality/quality.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'checkstyle' 2 | apply plugin: 'pmd' 3 | apply plugin: 'findbugs' 4 | 5 | check.dependsOn 'compileDebugJava', 'checkstyle', 'findbugs', 'pmd' 6 | 7 | android { 8 | lintOptions { 9 | abortOnError false 10 | xmlOutput file("$buildDir/reports/lint/lint-report.xml") 11 | htmlOutput file("$buildDir/reports/lint/lint-report.html") 12 | } 13 | } 14 | 15 | checkstyle { 16 | toolVersion = "5.7" 17 | } 18 | 19 | task checkstyle(type: Checkstyle) { 20 | configFile file('../config/quality/checkstyle/checkstyle.xml') 21 | source 'src/org' 22 | include '**/*.java' 23 | exclude '**/gen/**' 24 | ignoreFailures = true 25 | classpath = files() 26 | 27 | doLast { 28 | ant.xslt(in: "$buildDir/reports/checkstyle/checkstyle.xml", 29 | style:"../config/quality/checkstyle/checkstyle.xsl", 30 | out:"$buildDir/reports/checkstyle/checkstyle.html" 31 | ) 32 | } 33 | } 34 | 35 | findbugs { 36 | toolVersion = "3.0.0" 37 | } 38 | 39 | task findbugs(type: FindBugs) { 40 | excludeFilter file('../config/quality/findbugs/findbugs-filter-exclude.xml') 41 | ignoreFailures = true 42 | classes = fileTree('build/intermediates/classes/debug/org') 43 | source = fileTree('src/org') 44 | effort = 'max' 45 | 46 | classpath = files() 47 | 48 | reports { 49 | xml.enabled = false 50 | html.enabled = true 51 | } 52 | } 53 | pmd { toolVersion = '5.1.1' } 54 | 55 | task pmd(type: Pmd) { 56 | ignoreFailures = true 57 | File ruleSetsDir = file('../config/quality/pmd/rulesets') 58 | ruleSetFiles = files(ruleSetsDir.listFiles()) 59 | // ruleSetFiles = files('../config/quality/pmd/pmd-configuration.xml') 60 | // ruleSets = ["basic", "braces", "strings"] 61 | source = fileTree("src/org") 62 | } -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include 'ACalDAV' --------------------------------------------------------------------------------