/* ** ** Copyright 2009, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. ** You may obtain a copy of the License at ** ** http://www.apache.org/licenses/LICENSE-2.0 ** ** Unless required by applicable law or agreed to in writing, software ** distributed under the License is distributed on an "AS IS" BASIS, ** See the License for the specific language governing permissions and ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** limitations under the License. */ package com.android.calendar; import static android.provider.CalendarContract.EXTRA_EVENT_BEGIN_TIME; import static android.provider.CalendarContract.EXTRA_EVENT_END_TIME; import static android.provider.CalendarContract.Attendees.ATTENDEE_STATUS; import static android.provider.CalendarContract.Attendees.ATTENDEE_STATUS_ACCEPTED; import static android.provider.CalendarContract.Attendees.ATTENDEE_STATUS_DECLINED; import static android.provider.CalendarContract.Attendees.ATTENDEE_STATUS_NONE; import static android.provider.CalendarContract.Attendees.ATTENDEE_STATUS_TENTATIVE; import android.app.Activity; import android.content.ActivityNotFoundException; import android.content.ContentUris; import android.content.Intent; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.provider.CalendarContract.Events; import android.text.TextUtils; import android.util.Base64; import android.util.Log; import com.android.calendarcommon.DateException; public class GoogleCalendarUriIntentFilter extends Activity { private static final String TAG = "GoogleCalendarUriIntentFilter"; private static final int EVENT_INDEX_ID = 0; private static final int EVENT_INDEX_START = 1; private static final int EVENT_INDEX_END = 2; private static final int EVENT_INDEX_DURATION = 3; private static final String[] EVENT_PROJECTION = new String[] { Events._ID, // 0 Events.DTSTART, // 1 Events.DTEND, // 2 Events.DURATION, // 3 }; /** * Extracts the ID from the eid parameter of a URI. * * The URI contains an "eid" parameter, which is comprised of an ID, followed by a space, * followed by some other stuff. This is Base64-encoded before being added to the URI. * * @param uri incoming request * @return the decoded ID */ private String extractEid(Uri uri) { try { String eid = uri.getQueryParameter("eid"); if (eid == null) { return null; } byte[] decodedBytes = Base64.decode(eid, Base64.DEFAULT); int spacePosn; for (spacePosn = 0; spacePosn < decodedBytes.length; spacePosn++) { if (decodedBytes[spacePosn] == ' ') { break; } } return new String(decodedBytes, 0, spacePosn); } catch (RuntimeException e) { Log.w(TAG, "Punting malformed URI " + uri); return null; } } @Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); Intent intent = getIntent(); if (intent != null) { Uri uri = intent.getData(); if (uri != null) { String eid = extractEid(uri); if (eid != null) { String selection = Events._SYNC_ID + " LIKE \"%/" + eid + "\""; Cursor eventCursor = managedQuery(Events.CONTENT_URI, EVENT_PROJECTION, selection, null, null); if (eventCursor != null && eventCursor.getCount() > 0) { if (eventCursor.getCount() > 1) { // TODO what to do when there's more than one match? // // Probably the case of multiple calendar having the // same event. // // If the intent has info about account (Gmail // hashes the account name in some cases), we can // try to match it. // // Otherwise, pull up the copy with higher permission level. Log.i(TAG, "NOTE: found " + eventCursor.getCount() + " matches on event with id='" + eid + "'"); } // Get info from Cursor while (eventCursor.moveToNext()) { int eventId = eventCursor.getInt(EVENT_INDEX_ID); long startMillis = eventCursor.getLong(EVENT_INDEX_START); long endMillis = eventCursor.getLong(EVENT_INDEX_END); if (endMillis == 0) { String duration = eventCursor.getString(EVENT_INDEX_DURATION); if (TextUtils.isEmpty(duration)) { continue; } try { Duration d = new Duration(); d.parse(duration); endMillis = startMillis + d.getMillis(); if (endMillis < startMillis) { continue; } } catch (DateException e) { continue; } } // Pick up attendee status action from uri clicked int attendeeStatus = ATTENDEE_STATUS_NONE; if ("RESPOND".equals(uri.getQueryParameter("action"))) { try { switch (Integer.parseInt(uri.getQueryParameter("rst"))) { case 1: // Yes attendeeStatus = ATTENDEE_STATUS_ACCEPTED; break; case 2: // No attendeeStatus = ATTENDEE_STATUS_DECLINED; break; case 3: // Maybe attendeeStatus = ATTENDEE_STATUS_TENTATIVE; break; } } catch (NumberFormatException e) { // ignore this error as if the response code // wasn't in the uri. } } // Send intent to calendar app Uri calendarUri = ContentUris.withAppendedId(Events.CONTENT_URI, eventId); intent = new Intent(Intent.ACTION_VIEW, calendarUri); intent.putExtra(EXTRA_EVENT_BEGIN_TIME, startMillis); intent.putExtra(EXTRA_EVENT_END_TIME, endMillis); if (attendeeStatus != ATTENDEE_STATUS_NONE) { intent.putExtra(ATTENDEE_STATUS, attendeeStatus); } startActivity(intent); finish(); return; } } } } // Can't handle the intent. Pass it on to the next Activity. try { startNextMatchingActivity(intent); } catch (ActivityNotFoundException ex) { // no browser installed? Just drop it. } } finish(); } }