google calendar 구글 칼렌더 연동해서 listview에 보여주는 어플을 개발하실때, 도움이 되라고 게시물을 씁니다.
다음 내용은 login, retrieve, xml parsing, display listview and create events들에 대한 소스 및 설명이며, java 언어에 대한 내용은 생략합니다. 일단 각 부분의 설명을 먼저 간략히 하고, 마지막엔 완성된 소스를 올리겠습니다.

아래 페이지에서 보다 자세한 내용들을 확인하시기 바랍니다.
http://code.google.com/intl/ko/apis/calendar/data/2.0/developers_guide_protocol.html
빨간색 주석은 위의 페이지에서 인용한 문장입니다.
파란색 글자들은 "예"입니다.

1. Login
        // http://code.google.com/intl/ko/apis/calendar/data/2.0/developers_guide_protocol.html#AuthClientLogin

        static final String mURLClientLogin = "https://www.google.com/accounts/ClientLogin";
        static String mAuthTokenCal;

        String userEmail = "your@google.com";
        String userPasswd = "yourPassword";
        // Identifies your client application. Should take the form companyName-applicationName-versionID
        String userSource = "package-class-version";
       
        HttpsURLConnection uc = (HttpsURLConnection) new URL(mURLClientLogin).openConnection();
        uc.setDoOutput(true);
        uc.setRequestMethod("POST");
        uc.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
        uc.setUseCaches(false);

        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(uc.getOutputStream()));
        bw.write(URLEncoder.encode("Email", "UTF-8") + "="
                + URLEncoder.encode(userEmail , "UTF-8") + "&"
                + URLEncoder.encode("Passwd", "UTF-8") + "="
                + URLEncoder.encode(userPasswd , "UTF-8") + "&"
                + URLEncoder.encode("source", "UTF-8") + "="
                + URLEncoder.encode(userSource , "UTF-8") + "&"
                + URLEncoder.encode("service", "UTF-8") + "="
                + URLEncoder.encode("cl", "UTF-8")
                );
        bw.flush();
        bw.close();

        BufferedReader in = new BufferedReader(new InputStreamReader(uc.getInputStream()));
        // If the authentication request fails, you'll receive an HTTP 403 Forbidden status code.
        if (uc.getResponseCode() == HttpsURLConnection.HTTP_FORBIDDEN) {
            return false;
        }

        in.readLine();
        in.readLine();
        // The Auth value is the authorization token that you'll send to Calendar with your request, so keep a copy of that value.
        mAuthTokenCal = in.readLine().substring(5);
        in.close();

2. Retrieve events
        // http://code.google.com/intl/ko/apis/calendar/data/2.0/developers_guide_protocol.html#RetrievingEvents

        // 아래 communicate()함수는 retrieve/create할때 공통적으로 쓰이는 코드입니다.
        HttpURLConnection communicate(String url) throws MalformedURLException, IOException {
            HttpURLConnection uc = (HttpURLConnection) new URL(url).openConnection();
            uc.setUseCaches(false);
            uc.setRequestMethod("GET");
            uc.setRequestProperty("Content-Type", "application/atom+xml");
            // http://code.google.com/intl/ko/apis/calendar/data/2.0/developers_guide_protocol.html#Versioning
            uc.setRequestProperty("GData-Version", "2");
            uc.setRequestProperty("Authorization", "GoogleLogin auth=" + mAuthTokenCal);
            return uc;
        }

        // 다음은 Retrieve events의 실제 내용입니다.
        // For mURLRetrieveCal, check this page - http://code.google.com/intl/ko/apis/calendar/data/2.0/reference.html#Visibility
        static final String mURLRetrieveCal = "http://www.google.com/calendar/feeds/default/private/full";
        String url;

        try {
            HttpURLConnection uc = communicate(mURLRetrieveCal);
            if (uc != null) {
                // When you send that GET request, Calendar may return an HTTP 302 redirect
                if (uc.getResponseCode() == HttpURLConnection.HTTP_MOVED_TEMP) {
                    url = uc.getHeaderField("Location");                                // redirect 할 주소를 다시 가져옵니다.
                    uc = communicate(url);                                                    // 새 주소로 다시 보냅니다.
                    if (uc.getResponseCode() == HttpURLConnection.HTTP_OK) {   // 성공했다면,
                        getXMLDocument(uc.getInputStream());                     // xml 을 parsing합니다.
                    }
                    else {
                        return false; // failed
                    }
                }
                else if (uc.getResponseCode() == HttpURLConnection.HTTP_OK) {   // redirect할 필요가 없는 경우입니다.
                    getXMLDocument(type, uc.getInputStream());
                }
                else {
                    return false; // failed
                }
            }
            else {
                return false; // failed
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
            return false; // failed
        } catch (IOException e) {
            e.printStackTrace();
            return false; // failed
        }

3. pasrsing XML
        // xml parsring은 다양하니, 필요한 parser를 사용하시면됩니다.
        // 여기서는 sax2를 사용했고, handler로 GoogleCalendarSAXHandler 를 구현하였습니다.

    import org.xml.sax.Attributes;
    import org.xml.sax.InputSource;
    import org.xml.sax.XMLReader;
    import org.xml.sax.helpers.DefaultHandler;
    import org.xml.sax.helpers.XMLReaderFactory;

    void getXMLDocument(InputStream inputStream) {
        try {
            System.setProperty("org.xml.sax.driver","org.xmlpull.v1.sax2.Driver"); // 이건 편의상 여기두었습니다만, 한번만 불러주면 되니까, 여기 말고 좀 더 상위에서 불러주면 좋겠습니다.
            XMLReader xr = XMLReaderFactory.createXMLReader();
            GoogleCalendarSAXHandler handlerCal = new GoogleCalendarSAXHandler(mList);
            xr.setContentHandler(handlerCal);
            xr.setErrorHandler(handlerCal);
            InputSource inputSource = new InputSource(inputStream);
            xr.parse(inputSource);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

class GoogleCalendarSAXHandler extends DefaultHandler
{
    static final String TAG_ENTRY = "entry";
    static final String TAG_EID = "id";
    static final String TAG_TITLE = "title";
    static final String TAG_CONTENT = "content";
    static final String TAG_WHERE = "gd:where";
    static final String TAG_WHEN = "gd:when";
    static final String ATT_VALUESTRING = "valueString";
    static final String ATT_ENDTIME = "endTime";
    static final String ATT_STARTTIME = "startTime";
   
    private int mMode = 0;
    private EventData mEventData = new EventData();
    private ArrayList<EvenData> mEventDataList = null;
   
    public GoogleCalendarSAXHandler (ArrayList<EvenData> list) {
        super();
        mEventDataList = list;
    }
   
    @Override
    public void startDocument () {
        mEventDataList.clear();
        // 문서를 읽기 시작합니다.
    }

    @Override
    public void endDocument () {
        // 문서를 다 읽었습니다.
    }

    @Override
    public void startElement (String uri, String lName, String qName, Attributes atts) {
        if (TAG_ENTRY.equals(qName)) {
            mEventData.clear();
            mMode = 1;  // mMode는 sax2 parser속성 상 parser tree를 만들지않기 때문에, 바로 읽으면서 필요한 정보의 위치를 확인하기 위해 사용하는 변수입니다.
        }
        else if(TAG_EID.equals(qName)) {
            if (mMode > 0) mMode = 2;
        }
        else if(TAG_TITLE.equals(qName)) {
            if (mMode > 0) mMode = 3;
        }
        else if(TAG_CONTENT.equals(qName)) {
            if (mMode > 0) mMode = 4;
        }
        else if(TAG_WHERE.equals(qName)) {
            if (mMode > 0) {
                mMode = 5;
                for (int i=0; i<atts.getLength(); ++i) {
                    if (ATT_VALUESTRING.equals(atts.getQName(i))) {
                        mEventData.setWhere(atts.getValue(i)); // where
                    }
                }
            }
        }
        else if(TAG_WHEN.equals(qName)) {
            if (mMode > 0) {
                mMode = 6;
                for (int i=0; i<atts.getLength(); ++i) {
                    if (ATT_ENDTIME.equals(atts.getQName(i))) {
                        mEventData.setEndTime(atts.getValue(i)); // endtime
                    }
                    else if (ATT_STARTTIME.equals(atts.getQName(i))) {
                        mEventData.setStartTime(atts.getValue(i)); // starttime
                    }
                }
            }
        }
    }

    @Override
    public void endElement (String uri, String name, String qName) {
        if (TAG_ENTRY.equals(name)) {
            mEventDataList.add(mEventData); // event들을 리스트에 넣습니다.
            mMode = 0;
        }
        if (mMode > 1) mMode = 1;
    }

    @Override
    public void characters (char ch[], int start, int length) {
        switch (mMode) {
        case 2:
            mEventData.setEID(new String(ch, start, length)); // eid
            mMode = 1;
            break;
        case 3:
            mEventData.setTitle(new String(ch, start, length)); // title
            mMode = 1;
            break;
        case 4:
            mEventData.setContent(new String(ch, start, length)); // content
            mMode = 1;
            break;
        }
    }
}

4. display listview

 아 더워서 더 못쓰겠다... 다음 계속....