Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I add a new phone calendar to Android?

The calendar app on Android can merge multiple separate calendars: local phone calendar, Google calendars, etc.

How can I add a new such calendar to the Android phone? I want to dynamically generate the events in that calendar without accessing any online resource like Google.

Edit: I'd like to support phones with Android 1.5 and 2.3.4. I'll probably get an update to 4.0 for the newer phone someday but who knows when that will be...

like image 459
Kempeth Avatar asked Jan 16 '12 15:01

Kempeth


2 Answers

I just managed to add a Calendar using the new API from ICS. Stefan's answer helped, but to be able to write to all columns, you have to do the operation as a sync adapter. You can do this from a normal app using CalendarContract.ACCOUNT_TYPE_LOCAL. The following code should work on ICS. Maybe some column values are not right. Check out the documentation of CalendarContract.Calendars. Unfortunately I cannot help you for older Android versions, but CalendarContract is only used for some constant string values. Maybe these also work on older versions.

Uri calUri = CalendarContract.Calendars.CONTENT_URI;
ContentValues cv = new ContentValues();
cv.put(CalendarContract.Calendars.ACCOUNT_NAME, yourAccountName);
cv.put(CalendarContract.Calendars.ACCOUNT_TYPE, CalendarContract.ACCOUNT_TYPE_LOCAL);
cv.put(CalendarContract.Calendars.NAME, yourInternalName);
cv.put(CalendarContract.Calendars.CALENDAR_DISPLAY_NAME, yourDisplayName);
cv.put(CalendarContract.Calendars.CALENDAR_COLOR, yourColor);
cv.put(CalendarContract.Calendars.CALENDAR_ACCESS_LEVEL, CalendarContract.Calendars.CAL_ACCESS_OWNER);
cv.put(CalendarContract.Calendars.OWNER_ACCOUNT, true);
cv.put(CalendarContract.Calendars.VISIBLE, 1);
cv.put(CalendarContract.Calendars.SYNC_EVENTS, 1);

calUri = calUri.buildUpon()
    .appendQueryParameter(CalendarContract.CALLER_IS_SYNCADAPTER, "true")
    .appendQueryParameter(CalendarContract.Calendars.ACCOUNT_NAME, ACCOUNT_NAME)
    .appendQueryParameter(CalendarContract.Calendars.ACCOUNT_TYPE, CalendarContract.ACCOUNT_TYPE_LOCAL)
    .build();
Uri result = this.getContentResolver().insert(calUri, cv);
like image 135
harsel Avatar answered Oct 23 '22 20:10

harsel


I have written the following activity (plus some resources, etc.) to insert a calendar (not synchronized) on the API level 15 emulator (because the calendar app there has no feature to add a calendar unlike the app on my phone (API 8), or I did not find it ...). The layout has to text fields for the calendar's name and display name, an add-button, and a status text view to give feedback after the insert. Make sure you have the permissions set in the manifest:

<uses-permission android:name="android.permission.WRITE_CALENDAR"/>
<uses-permission android:name="android.permission.READ_CALENDAR"/>

Here is Code:

public class CalUtilActivity extends Activity {
private EditText name;
private EditText display;
private TextView status;

@Override
public void onCreate(final Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    this.setContentView(R.layout.main);

    this.name = (EditText) this.findViewById(R.id.name);
    this.display = (EditText) this.findViewById(R.id.displayname);
    this.status = (TextView) this.findViewById(R.id.status);

    final Button b = (Button) this.findViewById(R.id.add);
    b.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(final View v) {
            CalUtilActivity.this.addCalendar();
        }
    });
}

private void addCalendar() {
    final String cname = this.name.getText().toString();
    final String dname = this.display.getText().toString();
    if( cname.length() == 0 || dname.length() == 0 ) {
        this.status.setText(this.getResources().getString(R.string.errorNames));
        return;
    }
    this.status.setText("");

    final Uri calUri = CalendarContract.Calendars.CONTENT_URI;
    final ContentValues v = new ContentValues();
    v.put(CalendarContract.Calendars.NAME, cname);
    v.put(CalendarContract.Calendars.CALENDAR_DISPLAY_NAME, dname);
    v.put(CalendarContract.Calendars.VISIBLE, 1);

    final Uri result = this.getContentResolver().insert(calUri, v);

    this.status.setText(result.toString());
}

}

For API 13 and before you cannot use the content provider, you have to access the database directly. To add a calendar you must add a row to the table Calendars, which is defined according to the following create statement

CREATE TABLE Calendars (_id INTEGER PRIMARY KEY,_sync_account TEXT,_sync_account_type TEXT,_sync_id TEXT,_sync_version TEXT,_sync_time TEXT,_sync_local_id INTEGER,_sync_dirty INTEGER,_sync_mark INTEGER,url TEXT,name TEXT,displayName TEXT,hidden INTEGER NOT NULL DEFAULT 0,color INTEGER,access_level INTEGER,selected INTEGER NOT NULL DEFAULT 1,sync_events INTEGER NOT NULL DEFAULT 0,location TEXT,timezone TEXT,ownerAccount TEXT, organizerCanRespond INTEGER NOT NULL DEFAULT 1);

Setting the _id, name, and displayName should work if you do not need to synchronize the calendar. However, you cannot test on the emulator, because the calendar app ands its database is missing. And device vendors might have modified the database theoretically, but since there lots of calendar application available I personally do not think that they have modified the database schema.

like image 27
Stefan Avatar answered Oct 23 '22 19:10

Stefan