Android und der Content Provider des Kalenders

Android

Für ein Projekt im Kurs „Mobile Computing“ habe ich mich zuletzt mit dem Kalender von Android-Geräten beschäftigen. Dabei gab es den einen oder anderen Stolperstein.
Entwickelt habe ich hauptsächlich auf einem Motorola Milestone mit Version 2.1.

Zugriff auf den Content Provider

Es ist möglich an die Daten des Kalenders zu gelangen, jedoch hat Google wohl noch keine Dokumentation dafür freigegeben, da es dort noch Änderungen in zukünftigen Versionen geben kann – oder so ähnlich irgendwie. Jedenfalls es geht und es geht so:

Im AndroidManifest.xml trägt man die Erlaubnis für Lese- und Schreibzugriff auf den Kalender ein. Schreiben nur, wenn man es benötigt. In diesem Artikel ist dies nicht der Fall.

<manifest>
	[…]
	<uses-permission android:name="android.permission.READ_CALENDAR" />
	<uses-permission android:name="android.permission.WRITE_CALENDAR" />
</manifest>

Kommen wir zur URI des Content-Providers. Ab SDK-Version 8 (Android-Version 2.2) lautet diese content://com.android.calendar, davor war es content://calendar. Eine Fall­unterscheidung muss also sein.

String URI_CALENDAR = "content://";
if( Build.VERSION.SDK_INT >= 8 ) {
	URI_CALENDAR += "com.android.calender";
}
else {
	URI_CALENDAR += "calendar";
}

Die verfügbaren Felder für die Anfrage an den Provider lassen sich aus dem Google-Code herauslesen. So erhält man einen Cursor über die Kalender:

/* Wichtige Felder:
 * _id, displayName, hidden, location, name, ownerAccount, url
 */
private static String[] calColumns = new String[]{
	"_id", "name", "displayName", "url"
};

public Cursor getCalendars() {
	String cals = URI_CALENDAR + "/content";
	Uri calendars = Uri.parse( cals );
	Cursor calCursor = getContentResolver().query(
		calendars, calColumns, null, null, null
	);
	return calCursor;
}

Möchte man Zugriff auf die Termine, sieht der Code dafür – vorausgesetzt man kennt die Kalender-ID – so aus:

/* Wichtige Felder:
 * allDay, begin, calendar_id, deleted, description, dtstart, dtend, duration,
 * exdate, exrule, hasAlarm, htmlUri, end, eventLocation, eventStatus,
 * eventTimezone, lastDate, rdate, rrule, title, transparency, visibility 
 */
private static String[] calEventColumns = new String[]{
	"_id", "title", "description", "begin", "end"
};

public Cursor getCalendar( int id ) {
	String uriEvents = URI_CALENDAR + "/instances/when";
	Uri.Builder builder = Uri.parse( uriEvents ).buildUpon();

	long now = new Date().getTime();
	ContentUris.appendId( builder, now - DateUtils.WEEK_IN_MILLIS );
	ContentUris.appendId( builder, now + DateUtils.WEEK_IN_MILLIS );

	Cursor eventCursor = getContentResolver().query(
		builder.build(),
		calEventColumns,
		"Calendars._id=" + id,
		null,
		"startDay ASC, startMinute ASC"
	);
	return eventCursor;
}

Überprüfen, ob Kalender installiert

Mein erster Ansatz war, die vorhandenen Activities nach „com.android.calendar“ zu durchsuchen. Dies ging auch recht gut, nur auf einem HTC-Gerät wurde kein Kalender gefunden. Warum? Dort heißt die Activity „com.htc.calendar“. Ganz großes Kino. Darf ich davon ausgehen, dass andere Hersteller sich genauso ein eigenes Süppchen kochen?

Der zweite Ansatz – und in jeder Hinsicht sinnvoller – ist nun, die vorhandenen Content-Provider zu durchforsten. Je nach Android-Version eben wieder mit Fallunterscheidung, dafür, wie ich doch hoffen möchte, herstellerunabhängig. Zumindest funktioniert es so nun auf dem Motorola (2.1) und dem HTC (2.2).

public boolean isCalendarProviderAvailable() {
	String uriCalProvider = URI_CALENDAR.replace( "content://", "" );
	List pckgList = getPackageManager().getInstalledPackages(
			PackageManager.GET_PROVIDERS );

	for( PackageInfo pckgInfo : pckgList ) {
		ProviderInfo[] provInfo = pckgInfo.providers;
		if( provInfo != null ) {
			for( ProviderInfo prIn : provInfo ) {
				if( prIn.authority.equals( uriCalProvider ) ) {
					return true;
				}
			}
		}
	}

	return false;
}

Testen im Emulator

Den Android-Emulator gibt es kostenlos unter developer.android.com/sdk/. Es fehlen nur alle Google-Apps wie Mail, Market, Calendar … Well, fuck. Ein gewiefter Zeitgenosse hat es trotzdem geschafft, ein Systembild für den Emulator anzupassen. Wie es geht, lest bei ihm: techdroid.kbeanie.com/2009/11/android-market-on-emulator.html. System-Datei herunterladen (Link dort im Artikel) und nach Anleitung ins Verzeichnis kopieren. Mehr ist es nicht. Leider ist es bisher nur für 1.5 und 1.6 möglich.



Quellen