FileDocCategorySizeDatePackage
VCalManager.javaAPI DocAndroid 1.5 API14180Wed May 06 22:42:46 BST 2009com.android.mms.activity

VCalManager.java

/*
 * Copyright (C) 2007-2008 Esmertec AG.
 * Copyright (C) 2007-2008 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,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.mms.activity;

import com.google.android.mms.util.SqliteWrapper;

import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.provider.Calendar;
import android.provider.Calendar.Calendars;
import android.syncml.pim.PropertyNode;
import android.syncml.pim.VDataBuilder;
import android.syncml.pim.VNode;
import android.syncml.pim.vcalendar.CalendarStruct;
import android.syncml.pim.vcalendar.VCalComposer;
import android.syncml.pim.vcalendar.VCalException;
import android.syncml.pim.vcalendar.VCalParser;
import android.text.format.Time;
import android.util.Log;

import java.util.HashMap;
import java.util.Set;

/**
 * Provides the methods to handle the content provider of calendars for MMS activity client.
 */
public class VCalManager {
    private static final String TAG = "VCalManager";
    private static final String TIME_FORMAT_STRING = "%Y-%m-%d %H:%M:%S";

    private ContentValues mVCalValues;
    private final Context mContext;
    private final ContentResolver mResolver;
    private Uri mUri;
    private HashMap<String, Long> mCalendars = null;

    /**
     * Constructor.
     * @param context the context of the activity.
     * @param data Calendar data.
     * @throws IllegalArgumentException
     */
    public VCalManager(Context context, String data) throws IllegalArgumentException {
        if (context == null) {
            throw new IllegalArgumentException();
        }

        mContext = context;
        mResolver = mContext.getContentResolver();
        mVCalValues = parseVCalendar(data);
    }

    /**
     * Constructor.
     * @param context the context of the activity.
     * @param uri the stored event URI.
     */
    public VCalManager(Context context, Uri uri) {
        mContext = context;
        mResolver = mContext.getContentResolver();
        mUri = uri;
    }

    public String[] getCalendars() {
        if (mCalendars == null) {
            Cursor cursor = SqliteWrapper.query(mContext, mResolver, Calendars.CONTENT_URI,
                                new String[] {Calendars._ID, Calendars.DISPLAY_NAME},
                                null, null, null);

            if (null == cursor) {
                return null;
            }

            mCalendars = new HashMap<String, Long>();
            try {
                while (cursor.moveToNext()) {
                    long id = cursor.getLong(cursor.getColumnIndexOrThrow(Calendars._ID));
                    String name = cursor.getString(cursor.getColumnIndexOrThrow(Calendars.DISPLAY_NAME));
                    mCalendars.put(name, id);
                }
            } finally {
                cursor.close();
            }
        }

        Set<String> keySet = mCalendars.keySet();
        int size = keySet.size();
        if (size <= 0) {
            return null;
        }

        String[] calendarArray = new String[size];
        keySet.toArray(calendarArray);
        return calendarArray;
    }

    /**
     * Load the formatted data of the stored calendar event.
     * @return the formatted data string.
     */
    public String getData() {
        if (mUri == null) {
            Log.e(TAG, "Bad content URI.");
            return null;
        }
        Cursor c = SqliteWrapper.query(mContext, mResolver, mUri,
                        null, null, null, null);

        String uid = mUri.toString();
        if (c == null) {
            Log.e(TAG, "Cannot query the content from " + mUri);
            return null;
        }
        try {
            c.moveToFirst();
            CalendarStruct calStruct = new CalendarStruct();

            calStruct.timezone = c.getString(c.getColumnIndexOrThrow(Calendar.Events.EVENT_TIMEZONE));

            //event list:
            CalendarStruct.EventStruct evtStruct = new CalendarStruct.EventStruct();

            evtStruct.uid = uid;
            evtStruct.description = c.getString(c.getColumnIndexOrThrow(
                    Calendar.Events.DESCRIPTION));
            evtStruct.dtend = convertLongToRFC2445DateTime(c.getLong(c.getColumnIndexOrThrow(
                    Calendar.Events.DTEND)));
            evtStruct.dtstart = convertLongToRFC2445DateTime(c.getLong(c.getColumnIndexOrThrow(
                    Calendar.Events.DTSTART)));
            evtStruct.duration = c.getString(c.getColumnIndexOrThrow(
                    Calendar.Events.DURATION));
            evtStruct.event_location = c.getString(c.getColumnIndexOrThrow(
                    Calendar.Events.EVENT_LOCATION));
            evtStruct.has_alarm = c.getString(c.getColumnIndexOrThrow(
                    Calendar.Events.HAS_ALARM));
            evtStruct.last_date = convertLongToRFC2445DateTime(c.getLong(c.getColumnIndexOrThrow(
                    Calendar.Events.LAST_DATE)));
            evtStruct.rrule = c.getString(c.getColumnIndexOrThrow(
                    Calendar.Events.RRULE));
            evtStruct.status = c.getString(c.getColumnIndexOrThrow(
                    Calendar.Events.STATUS));
            evtStruct.title = c.getString(c.getColumnIndexOrThrow(
                    Calendar.Events.TITLE));

            if (!isNull(evtStruct.has_alarm)) {
                getReminders(evtStruct, Uri.parse(uid).getLastPathSegment());
            }

            calStruct.addEventList(evtStruct);

            try{    //build vcalendar:
                VCalComposer composer = new VCalComposer();

                return composer.createVCal(calStruct, VCalComposer.VERSION_VCAL10_INT);
            } catch (Exception e) {
                return null;
            }
        } finally {
            c.close();
        }
    }

    /**
     * Get the name of the calendar event with ".vcs" suffix.
     * @return the name of the calendar event.
     */
    public String getName() {
        if (mUri == null) {
            Log.e(TAG, "Bad content URI.");
            return null;
        }

        Cursor c = SqliteWrapper.query(mContext, mResolver, mUri,
                        null, null, null, null);
        if (c == null) {
            Log.e(TAG, "Cannot query the content from " + mUri);
            return null;
        }
        try {
            c.moveToFirst();
            return c.getString(c.getColumnIndexOrThrow(Calendar.Events.TITLE)) + ".vcs";
        } finally {
            c.close();
        }
    }

    /**
     * Save the calendar data to local database.
     *
     * @param calendarName the calendar into which the vCal is saved.
     *      By calling method getCalendars(), user can get all calendar
     *      names as an string array.
     * @return true if success, otherwise return false.
     */
    public Uri save(String calendarName) {
        Long id = mCalendars.get(calendarName);
        if (null == id) {
            return null;
        }

        mVCalValues.put(Calendar.Events.CALENDAR_ID, id);
        return SqliteWrapper.insert(mContext, mResolver,
                    Calendar.Events.CONTENT_URI, mVCalValues);
    }

    /**
     * Get the title of the calendar event.
     * @return the title.
     */
    public String getTitle() {
        return (String) mVCalValues.get(Calendar.Events.TITLE);
    }

    /**
     * Get the event location of the calendar event.
     * @return the event location.
     */
    public String getEventLocation() {
        return (String) mVCalValues.get(Calendar.Events.EVENT_LOCATION);
    }

    /**
     * Get the description of the calendar event.
     * @return the description.
     */
    public String getDescription() {
        return (String) mVCalValues.get(Calendar.Events.DESCRIPTION);
    }

    /**
     * Get the start time of the calendar event.
     * @return the start time formatted as "%Y-%m-%d %H:%M:%S".
     */
    public String getDateTimeStart() {
        Long start = (Long) mVCalValues.get(Calendar.Events.DTSTART);
        if (start == null) {
            return null;
        }
        Time time = new Time();
        time.set(start);
        return time.format(TIME_FORMAT_STRING);
    }

    /**
     * Get the end time of the calendar event.
     * @return the end time formatted as "%Y-%m-%d %H:%M:%S".
     */
    public String getDateTimeEnd() {
        Long end = (Long) mVCalValues.get(Calendar.Events.DTEND);
        if (end == null) {
            return null;
        }
        Time time = new Time();
        time.set(end);
        return time.format(TIME_FORMAT_STRING);
    }

    /**
     * Get the duration of the calendar event.
     * @return the duration which is NOT formatted as "%Y-%m-%d %H:%M:%S".
     */
    public String getDuration() {
        return (String) mVCalValues.get(Calendar.Events.DURATION);
    }

    /**
     * Get the rule of the calendar event.
     * @return the rule.
     */
    public String getRepeatRule() {
        return (String) mVCalValues.get(Calendar.Events.RRULE);
    }

    /**
     * Get the completed time of the calendar event.
     * @return the completed time formatted as "%Y-%m-%d %H:%M:%S".
     */
    public String getCompleted() {
        Long complete = (Long) mVCalValues.get(Calendar.Events.LAST_DATE);
        if (complete == null) {
            return null;
        }
        Time time = new Time();
        time.set(complete);
        return time.format(TIME_FORMAT_STRING);
    }

    private ContentValues parseVCalendar(String data) {
        VCalParser parser = new VCalParser();
        VDataBuilder builder = new VDataBuilder();

        if (null == data) {
            return null;
        }

        try {
            parser.parse(data, builder);
        } catch (VCalException e) {
            Log.e(TAG, "VCalException: ", e);
            return null;
        }

        String curCalendarId = "";
        for (VNode vnode : builder.vNodeList) {
            // VCALENDAR field MUST present before VENENT and VTODO
            if (vnode.VName.equalsIgnoreCase("VCALENDAR")) {
                // If no Calendar, just set -1 as CalendarId, because user
                // should view the content even if no calendar created.
                curCalendarId = String.valueOf(getFirstIDFromCalendar());
            } else if (vnode.VName.equalsIgnoreCase("VEVENT") ||
                        vnode.VName.equalsIgnoreCase("VTODO")) {
                return setEventMap(vnode, curCalendarId);
            }
        }

        return null;
    }

    private static ContentValues setEventMap(VNode vnode, String calId) {
        ContentValues values = new ContentValues();

        values.put(Calendar.Events.CALENDAR_ID, calId);
        for (PropertyNode prop : vnode.propList) {
            if (prop.propValue != null) {
                Time time = new Time();
                if (prop.propName.equalsIgnoreCase("DESCRIPTION")) {
                    values.put(Calendar.Events.DESCRIPTION, prop.propValue);
                } else if (prop.propName.equalsIgnoreCase("DTEND")) {
                    time.parse(prop.propValue);
                    values.put(Calendar.Events.DTEND, time.toMillis(false /* use isDst */));
                } else if (prop.propName.equalsIgnoreCase("DTSTART")) {
                    time.parse(prop.propValue);
                    values.put(Calendar.Events.DTSTART, time.toMillis(false /* use isDst */));
                } else if (prop.propName.equalsIgnoreCase("SUMMARY")) {
                    values.put(Calendar.Events.TITLE, prop.propValue);
                } else if (prop.propName.equalsIgnoreCase("LOCATION")) {
                    values.put(Calendar.Events.EVENT_LOCATION, prop.propValue);
                } else if (prop.propName.equalsIgnoreCase("DUE")) {
                    values.put(Calendar.Events.DURATION, prop.propValue);
                } else if (prop.propName.equalsIgnoreCase("RRULE")) {
                    values.put(Calendar.Events.RRULE, prop.propValue);
                } else if (prop.propName.equalsIgnoreCase("COMPLETED")) {
                    time.parse(prop.propValue);
                    values.put(Calendar.Events.LAST_DATE, time.toMillis(false /* use isDst */));
                }
            }
        }
        return values;
    }

    private static boolean isNull(String str) {
        if ((str == null) || str.trim().equals("")) {
            return true;
        }
        return false;
    }

    private static String convertLongToRFC2445DateTime(long mills) {
        Time time = new Time();

        time.set(mills);
        return time.format("%Y%m%dT%H%M%SZ");
    }

    private void getReminders(CalendarStruct.EventStruct evtStruct, String localid) {
        Cursor c = SqliteWrapper.query(mContext, mResolver, Calendar.Reminders.CONTENT_URI,
                        null, "event_id=" + localid, null, null);
        String data = "";
        while ((c != null) && c.moveToNext()) {
            data = c.getString(c.getColumnIndexOrThrow(Calendar.Reminders.METHOD));
            evtStruct.addReminderList(data);
        }
        if (c != null) {
            c.close();
        }
    }

    private int getFirstIDFromCalendar() {
        Cursor c = SqliteWrapper.query(mContext, mResolver, Calendar.Calendars.CONTENT_URI,
                        null, null, null, null);

        if (c != null) {
            while (c.moveToNext()) {
                int id = c.getInt(c.getColumnIndexOrThrow("_id"));
                c.close();
                return id;
            }
            c.close();
        }
        return -1;
    }
}