@@ -39,6 +39,8 @@ import com.builttoroam.devicecalendar.common.ErrorCodes.Companion as EC
3939import com.builttoroam.devicecalendar.common.ErrorMessages.Companion as EM
4040import org.dmfs.rfc5545.recur.Freq as RruleFreq
4141import org.dmfs.rfc5545.recur.RecurrenceRule as Rrule
42+ import android.provider.CalendarContract.Colors
43+ import androidx.collection.SparseArrayCompat
4244
4345private const val RETRIEVE_CALENDARS_REQUEST_CODE = 0
4446private const val RETRIEVE_EVENTS_REQUEST_CODE = RETRIEVE_CALENDARS_REQUEST_CODE + 1
@@ -625,6 +627,8 @@ class CalendarDelegate(binding: ActivityPluginBinding?, context: Context) :
625627 values.put(Events .DTEND , end)
626628 values.put(Events .EVENT_END_TIMEZONE , endTimeZone)
627629 values.put(Events .DURATION , duration)
630+ values.put(Events .EVENT_COLOR_KEY , event.eventColorKey)
631+ values.put(Events .EVENT_COLOR , event.eventColor)
628632 return values
629633 }
630634
@@ -938,6 +942,8 @@ class CalendarDelegate(binding: ActivityPluginBinding?, context: Context) :
938942 val endTimeZone = cursor.getString(Cst .EVENT_PROJECTION_END_TIMEZONE_INDEX )
939943 val availability = parseAvailability(cursor.getInt(Cst .EVENT_PROJECTION_AVAILABILITY_INDEX ))
940944 val eventStatus = parseEventStatus(cursor.getInt(Cst .EVENT_PROJECTION_STATUS_INDEX ))
945+ val eventColor = cursor.getInt(Cst .EVENT_PROJECTION_EVENT_COLOR_INDEX )
946+ val eventColorKey = cursor.getInt(Cst .EVENT_PROJECTION_EVENT_COLOR_KEY_INDEX )
941947 val event = Event ()
942948 event.eventTitle = title ? : " New Event"
943949 event.eventId = eventId.toString()
@@ -953,6 +959,8 @@ class CalendarDelegate(binding: ActivityPluginBinding?, context: Context) :
953959 event.eventEndTimeZone = endTimeZone
954960 event.availability = availability
955961 event.eventStatus = eventStatus
962+ event.eventColor = if (eventColor == 0 ) null else eventColor
963+ event.eventColorKey = if (eventColorKey == 0 ) null else eventColorKey
956964
957965 return event
958966 }
@@ -1125,6 +1133,73 @@ class CalendarDelegate(binding: ActivityPluginBinding?, context: Context) :
11251133 return reminders
11261134 }
11271135
1136+ /* *
1137+ * load available event colors for the given account name
1138+ * unable to find official documentation, so logic is based on https://android.googlesource.com/platform/packages/apps/Calendar.git/+/refs/heads/pie-release/src/com/android/calendar/EventInfoFragment.java
1139+ **/
1140+ private fun retrieveColors (accountName : String , colorType : Int ): List <Pair <Int , Int >> {
1141+ val contentResolver: ContentResolver ? = _context ?.contentResolver
1142+ val uri: Uri = Colors .CONTENT_URI
1143+ val colors = mutableListOf<Int >()
1144+ val displayColorKeyMap = SparseArrayCompat <Int >()
1145+
1146+ val projection = arrayOf(
1147+ Colors .COLOR ,
1148+ Colors .COLOR_KEY ,
1149+ )
1150+
1151+ // load only event colors for the given account name
1152+ val selection = " ${Colors .COLOR_TYPE } = ? AND ${Colors .ACCOUNT_NAME } = ?"
1153+ val selectionArgs = arrayOf(colorType.toString(), accountName)
1154+
1155+
1156+ val cursor: Cursor ? = contentResolver?.query(uri, projection, selection, selectionArgs, null )
1157+ cursor?.use {
1158+ while (it.moveToNext()) {
1159+ val color = it.getInt(it.getColumnIndexOrThrow(Colors .COLOR ))
1160+ val colorKey = it.getInt(it.getColumnIndexOrThrow(Colors .COLOR_KEY ))
1161+ displayColorKeyMap.put(color, colorKey);
1162+ colors.add(color)
1163+ }
1164+ cursor.close();
1165+ // sort colors by colorValue, since they are loaded unordered
1166+ colors.sortWith(HsvColorComparator ())
1167+ }
1168+ return colors.map { Pair (it, displayColorKeyMap[it]!! ) }.toList()
1169+ }
1170+
1171+ fun retrieveEventColors (accountName : String ): List <Pair <Int , Int >> {
1172+ return retrieveColors(accountName, Colors .TYPE_EVENT )
1173+ }
1174+ fun retrieveCalendarColors (accountName : String ): List <Pair <Int , Int >> {
1175+ return retrieveColors(accountName, Colors .TYPE_CALENDAR )
1176+ }
1177+
1178+ fun updateCalendarColor (calendarId : Long , newColorKey : Int? , newColor : Int? ): Boolean {
1179+ val contentResolver: ContentResolver ? = _context ?.contentResolver
1180+ val uri: Uri = ContentUris .withAppendedId(CalendarContract .Calendars .CONTENT_URI , calendarId)
1181+ val values = ContentValues ().apply {
1182+ put(CalendarContract .Calendars .CALENDAR_COLOR_KEY , newColorKey)
1183+ put(CalendarContract .Calendars .CALENDAR_COLOR , newColor)
1184+ }
1185+ val rows = contentResolver?.update(uri, values, null , null )
1186+ return (rows ? : 0 ) > 0
1187+ }
1188+
1189+ /* *
1190+ * Compares colors based on their hue values in the HSV color space.
1191+ * https://android.googlesource.com/platform/prebuilts/fullsdk/sources/+/refs/heads/androidx-compose-integration-release/android-34/com/android/colorpicker/HsvColorComparator.java
1192+ */
1193+ private class HsvColorComparator : Comparator <Int > {
1194+ override fun compare (color1 : Int , color2 : Int ): Int {
1195+ val hsv1 = FloatArray (3 )
1196+ val hsv2 = FloatArray (3 )
1197+ Color .colorToHSV(color1, hsv1)
1198+ Color .colorToHSV(color2, hsv2)
1199+ return hsv1[0 ].compareTo(hsv2[0 ])
1200+ }
1201+ }
1202+
11281203 @Synchronized
11291204 private fun generateUniqueRequestCodeAndCacheParameters (parameters : CalendarMethodsParametersCacheModel ): Int {
11301205 // TODO we can ran out of Int's at some point so this probably should re-use some of the freed ones
0 commit comments