Home | History | Annotate | Download | only in calendar
      1 /*
      2 **
      3 ** Copyright 2009, The Android Open Source Project
      4 **
      5 ** Licensed under the Apache License, Version 2.0 (the "License");
      6 ** you may not use this file except in compliance with the License.
      7 ** You may obtain a copy of the License at
      8 **
      9 **     http://www.apache.org/licenses/LICENSE-2.0
     10 **
     11 ** Unless required by applicable law or agreed to in writing, software
     12 ** distributed under the License is distributed on an "AS IS" BASIS,
     13 ** See the License for the specific language governing permissions and
     14 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     15 ** limitations under the License.
     16 */
     17 
     18 package com.android.calendar;
     19 
     20 import static android.provider.CalendarContract.EXTRA_EVENT_BEGIN_TIME;
     21 import static android.provider.CalendarContract.EXTRA_EVENT_END_TIME;
     22 import static android.provider.CalendarContract.Attendees.ATTENDEE_STATUS;
     23 import static android.provider.CalendarContract.Attendees.ATTENDEE_STATUS_ACCEPTED;
     24 import static android.provider.CalendarContract.Attendees.ATTENDEE_STATUS_DECLINED;
     25 import static android.provider.CalendarContract.Attendees.ATTENDEE_STATUS_NONE;
     26 import static android.provider.CalendarContract.Attendees.ATTENDEE_STATUS_TENTATIVE;
     27 
     28 import android.app.Activity;
     29 import android.content.ActivityNotFoundException;
     30 import android.content.ContentUris;
     31 import android.content.Intent;
     32 import android.database.Cursor;
     33 import android.net.Uri;
     34 import android.os.Bundle;
     35 import android.provider.CalendarContract.Events;
     36 import android.text.TextUtils;
     37 import android.util.Base64;
     38 import android.util.Log;
     39 
     40 import com.android.calendarcommon.DateException;
     41 
     42 public class GoogleCalendarUriIntentFilter extends Activity {
     43     private static final String TAG = "GoogleCalendarUriIntentFilter";
     44 
     45     private static final int EVENT_INDEX_ID = 0;
     46     private static final int EVENT_INDEX_START = 1;
     47     private static final int EVENT_INDEX_END = 2;
     48     private static final int EVENT_INDEX_DURATION = 3;
     49 
     50     private static final String[] EVENT_PROJECTION = new String[] {
     51         Events._ID,      // 0
     52         Events.DTSTART,  // 1
     53         Events.DTEND,    // 2
     54         Events.DURATION, // 3
     55     };
     56 
     57     /**
     58      * Extracts the ID from the eid parameter of a URI.
     59      *
     60      * The URI contains an "eid" parameter, which is comprised of an ID, followed by a space,
     61      * followed by some other stuff.  This is Base64-encoded before being added to the URI.
     62      *
     63      * @param uri incoming request
     64      * @return the decoded ID
     65      */
     66     private String extractEid(Uri uri) {
     67         try {
     68             String eid = uri.getQueryParameter("eid");
     69             if (eid == null) {
     70                 return null;
     71             }
     72 
     73             byte[] decodedBytes = Base64.decode(eid, Base64.DEFAULT);
     74             int spacePosn;
     75             for (spacePosn = 0; spacePosn < decodedBytes.length; spacePosn++) {
     76                 if (decodedBytes[spacePosn] == ' ') {
     77                     break;
     78                 }
     79             }
     80             return new String(decodedBytes, 0, spacePosn);
     81         } catch (RuntimeException e) {
     82             Log.w(TAG, "Punting malformed URI " + uri);
     83             return null;
     84         }
     85     }
     86 
     87     @Override
     88     protected void onCreate(Bundle icicle) {
     89         super.onCreate(icicle);
     90 
     91         Intent intent = getIntent();
     92         if (intent != null) {
     93             Uri uri = intent.getData();
     94             if (uri != null) {
     95                 String eid = extractEid(uri);
     96                 if (eid != null) {
     97                     String selection = Events._SYNC_ID + " LIKE \"%/" + eid + "\"";
     98                     Cursor eventCursor = managedQuery(Events.CONTENT_URI, EVENT_PROJECTION,
     99                             selection, null, null);
    100 
    101                     if (eventCursor != null && eventCursor.getCount() > 0) {
    102                         if (eventCursor.getCount() > 1) {
    103                             // TODO what to do when there's more than one match?
    104                             //
    105                             // Probably the case of multiple calendar having the
    106                             // same event.
    107                             //
    108                             // If the intent has info about account (Gmail
    109                             // hashes the account name in some cases), we can
    110                             // try to match it.
    111                             //
    112                             // Otherwise, pull up the copy with higher permission level.
    113                             Log.i(TAG, "NOTE: found " + eventCursor.getCount()
    114                                     + " matches on event with id='" + eid + "'");
    115                         }
    116 
    117                         // Get info from Cursor
    118                         while (eventCursor.moveToNext()) {
    119                            int eventId = eventCursor.getInt(EVENT_INDEX_ID);
    120                             long startMillis = eventCursor.getLong(EVENT_INDEX_START);
    121                             long endMillis = eventCursor.getLong(EVENT_INDEX_END);
    122 
    123                             if (endMillis == 0) {
    124                                 String duration = eventCursor.getString(EVENT_INDEX_DURATION);
    125                                 if (TextUtils.isEmpty(duration)) {
    126                                     continue;
    127                                 }
    128 
    129                                 try {
    130                                     Duration d = new Duration();
    131                                     d.parse(duration);
    132                                     endMillis = startMillis + d.getMillis();
    133                                     if (endMillis < startMillis) {
    134                                         continue;
    135                                     }
    136                                 } catch (DateException e) {
    137                                     continue;
    138                                 }
    139                             }
    140 
    141                             // Pick up attendee status action from uri clicked
    142                             int attendeeStatus = ATTENDEE_STATUS_NONE;
    143                             if ("RESPOND".equals(uri.getQueryParameter("action"))) {
    144                                 try {
    145                                     switch (Integer.parseInt(uri.getQueryParameter("rst"))) {
    146                                     case 1: // Yes
    147                                         attendeeStatus = ATTENDEE_STATUS_ACCEPTED;
    148                                         break;
    149                                     case 2: // No
    150                                         attendeeStatus = ATTENDEE_STATUS_DECLINED;
    151                                         break;
    152                                     case 3: // Maybe
    153                                         attendeeStatus = ATTENDEE_STATUS_TENTATIVE;
    154                                         break;
    155                                     }
    156                                 } catch (NumberFormatException e) {
    157                                     // ignore this error as if the response code
    158                                     // wasn't in the uri.
    159                                 }
    160                             }
    161 
    162                             // Send intent to calendar app
    163                             Uri calendarUri = ContentUris.withAppendedId(Events.CONTENT_URI,
    164                                     eventId);
    165                             intent = new Intent(Intent.ACTION_VIEW, calendarUri);
    166                             intent.putExtra(EXTRA_EVENT_BEGIN_TIME, startMillis);
    167                             intent.putExtra(EXTRA_EVENT_END_TIME, endMillis);
    168                             if (attendeeStatus != ATTENDEE_STATUS_NONE) {
    169                                 intent.putExtra(ATTENDEE_STATUS, attendeeStatus);
    170                             }
    171                             startActivity(intent);
    172                             finish();
    173                             return;
    174                         }
    175                     }
    176                 }
    177             }
    178 
    179             // Can't handle the intent. Pass it on to the next Activity.
    180             try {
    181                 startNextMatchingActivity(intent);
    182             } catch (ActivityNotFoundException ex) {
    183                 // no browser installed? Just drop it.
    184             }
    185         }
    186         finish();
    187     }
    188 }
    189