| /* |
| * Copyright (C) 2007 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.calendar; |
| |
| import android.app.Activity; |
| import android.content.ContentResolver; |
| import android.content.ContentValues; |
| import android.content.Intent; |
| import android.database.Cursor; |
| import android.net.Uri; |
| import android.os.Bundle; |
| import android.pim.ICalendar; |
| import android.provider.Calendar; |
| import android.util.Config; |
| import android.util.Log; |
| import android.view.View; |
| import android.widget.ArrayAdapter; |
| import android.widget.Button; |
| import android.widget.ImageView; |
| import android.widget.Spinner; |
| import android.widget.TextView; |
| |
| import java.io.ByteArrayOutputStream; |
| import java.io.FileNotFoundException; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.util.ArrayList; |
| |
| public class IcsImportActivity extends Activity { |
| |
| private static final String TAG = "Calendar"; |
| |
| // TODO: consolidate this code with the EventActivity |
| private static class CalendarInfo { |
| public final long id; |
| public final String name; |
| |
| public CalendarInfo(long id, String name) { |
| this.id = id; |
| this.name = name; |
| } |
| |
| @Override |
| public String toString() { |
| return name; |
| } |
| } |
| |
| private View mView; |
| private Button mImportButton; |
| private Button mCancelButton; |
| private Spinner mCalendars; |
| private ImageView mCalendarIcon; |
| private TextView mNumEvents; |
| |
| private ICalendar.Component mCalendar = null; |
| |
| private View.OnClickListener mImportListener = new View.OnClickListener() { |
| public void onClick(View v) { |
| importCalendar(); |
| finish(); |
| } |
| }; |
| |
| private View.OnClickListener mCancelListener = new View.OnClickListener() { |
| public void onClick(View v) { |
| finish(); |
| } |
| }; |
| |
| @Override |
| protected void onCreate(Bundle icicle) { |
| super.onCreate(icicle); |
| setContentView(R.layout.ics_import_activity); |
| mView = findViewById(R.id.import_ics); |
| |
| mCalendarIcon = (ImageView) findViewById(R.id.calendar_icon); |
| mCalendars = (Spinner) findViewById(R.id.calendars); |
| populateCalendars(); |
| |
| mImportButton = (Button) findViewById(R.id.import_button); |
| mImportButton.setOnClickListener(mImportListener); |
| mCancelButton = (Button) findViewById(R.id.cancel_button); |
| mCancelButton.setOnClickListener(mCancelListener); |
| |
| mNumEvents = (TextView) findViewById(R.id.num_events); |
| |
| Intent intent = getIntent(); |
| String data = intent.getStringExtra("ics"); |
| if (data == null) { |
| Uri content = intent.getData(); |
| if (content != null) { |
| InputStream is = null; |
| try { |
| is = getContentResolver().openInputStream(content); |
| ByteArrayOutputStream baos = new ByteArrayOutputStream(); |
| byte[] buf = new byte[8096]; |
| int bytesRead = -1; |
| int pos = 0; |
| while ((bytesRead = is.read(buf)) != -1) { |
| baos.write(buf, pos, bytesRead); |
| pos += bytesRead; |
| } |
| data = new String(baos.toByteArray(), "UTF-8"); |
| } catch (FileNotFoundException fnfe) { |
| Log.w(TAG, "Could not open data.", fnfe); |
| } catch (IOException ioe) { |
| Log.w(TAG, "Could not read data.", ioe); |
| } finally { |
| if (is != null) { |
| try { |
| is.close(); |
| } catch (IOException ioe) { |
| Log.w(TAG, "Could not close InputStream.", ioe); |
| } |
| } |
| } |
| } |
| } |
| if (data == null) { |
| Log.w(TAG, "No iCalendar data to parse."); |
| finish(); |
| return; |
| } |
| parseCalendar(data); |
| } |
| |
| private void populateCalendars() { |
| ContentResolver cr = getContentResolver(); |
| Cursor c = cr.query(Calendar.Calendars.CONTENT_URI, |
| new String[] { Calendar.Calendars._ID, |
| Calendar.Calendars.DISPLAY_NAME, |
| Calendar.Calendars.SELECTED, |
| Calendar.Calendars.ACCESS_LEVEL }, |
| Calendar.Calendars.SELECTED + "=1 AND " |
| + Calendar.Calendars.ACCESS_LEVEL + ">=" |
| + Calendar.Calendars.CONTRIBUTOR_ACCESS, |
| null, null /* sort order */); |
| |
| ArrayList<CalendarInfo> items = new ArrayList<CalendarInfo>(); |
| try { |
| // TODO: write a custom adapter that wraps the cursor? |
| int idColumn = c.getColumnIndex(Calendar.Calendars._ID); |
| int nameColumn = c.getColumnIndex(Calendar.Calendars.DISPLAY_NAME); |
| while (c.moveToNext()) { |
| long id = c.getLong(idColumn); |
| String name = c.getString(nameColumn); |
| items.add(new CalendarInfo(id, name)); |
| } |
| } finally { |
| c.deactivate(); |
| } |
| |
| mCalendars.setAdapter(new ArrayAdapter<CalendarInfo>(this, |
| android.R.layout.simple_spinner_item, items)); |
| } |
| |
| private void parseCalendar(String data) { |
| mCalendar = null; |
| try { |
| mCalendar = ICalendar.parseCalendar(data); |
| } catch (ICalendar.FormatException fe) { |
| if (Config.LOGD) { |
| Log.d(TAG, "Could not parse iCalendar.", fe); |
| // TODO: show an error message. |
| finish(); |
| return; |
| } |
| } |
| if (mCalendar.getComponents() == null) { |
| Log.d(TAG, "No events in iCalendar."); |
| finish(); |
| return; |
| } |
| int numEvents = 0; |
| for (ICalendar.Component component : mCalendar.getComponents()) { |
| if ("VEVENT".equals(component.getName())) { |
| // TODO: display a list of the events (start time, title) in |
| // the UI? |
| ++numEvents; |
| } |
| } |
| // TODO: special-case a single-event calendar. switch to the |
| // EventActivity, once the EventActivity supports displaying data that |
| // is passed in via the extras. |
| // OR, we could flip things around, where the EventActivity handles ICS |
| // import by default, and delegates to the IcsImportActivity if it finds |
| // that there are more than one event in the iCalendar. that would |
| // avoid an extra activity launch for the expected common case of |
| // importing a single event. |
| mNumEvents.setText(Integer.toString(numEvents)); |
| } |
| |
| private void importCalendar() { |
| |
| ContentResolver cr = getContentResolver(); |
| |
| int numImported = 0; |
| ContentValues values = new ContentValues(); |
| |
| for (ICalendar.Component component : mCalendar.getComponents()) { |
| if ("VEVENT".equals(component.getName())) { |
| CalendarInfo calInfo = |
| (CalendarInfo) mCalendars.getSelectedItem(); |
| if (Calendar.Events.insertVEvent(cr, component, calInfo.id, |
| Calendar.Events.STATUS_CONFIRMED, values) != null) { |
| ++numImported; |
| } |
| } |
| } |
| // TODO: display how many were imported. |
| } |
| } |