1/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.providers.calendar;
18
19import android.app.ListActivity;
20import android.content.ContentResolver;
21import android.database.Cursor;
22import android.os.AsyncTask;
23import android.os.Bundle;
24import android.os.Handler;
25import android.provider.CalendarContract;
26import android.widget.ListAdapter;
27import android.widget.SimpleAdapter;
28import android.view.Window;
29
30import java.util.ArrayList;
31import java.util.HashMap;
32import java.util.List;
33import java.util.Map;
34
35/**
36 * Displays info about all the user's calendars, for debugging.
37 *
38 * The info is displayed as a ListActivity, where each entry has the calendar name
39 * followed by information about the calendar.
40 */
41public class CalendarDebug extends ListActivity {
42    private static final String[] CALENDARS_PROJECTION = new String[]{
43            CalendarContract.Calendars._ID,
44            CalendarContract.Calendars.CALENDAR_DISPLAY_NAME,
45    };
46    private static final int INDEX_ID = 0;
47    private static final int INDEX_DISPLAY_NAME = 1;
48
49    private static final String[] EVENTS_PROJECTION = new String[]{
50            CalendarContract.Events._ID,
51    };
52    private static final String KEY_TITLE = "title";
53    private static final String KEY_TEXT = "text";
54
55    private ContentResolver mContentResolver;
56    private ListActivity mActivity;
57
58    /**
59     *  Task to fetch info from the database and display as a ListActivity.
60     */
61    private class FetchInfoTask extends AsyncTask<Void, Void, List<Map<String, String>>> {
62        /**
63         * Starts spinner while task is running.
64         *
65         * @see #onPostExecute
66         * @see #doInBackground
67         */
68        @Override
69        protected void onPreExecute() {
70              setProgressBarIndeterminateVisibility(true);
71        }
72
73        /**
74         * Fetches debugging info from the database
75         * @param params Void
76         * @return a Map for each calendar
77         */
78        @Override
79        protected List<Map<String, String>> doInBackground(Void... params) {
80            Cursor cursor = null;
81            // items is the list of items to display in the list.
82            List<Map<String, String>> items = new ArrayList<Map<String, String>>();
83            try {
84                cursor = mContentResolver.query(CalendarContract.Calendars.CONTENT_URI,
85                        CALENDARS_PROJECTION,
86                        null, null /* selectionArgs */,
87                        CalendarContract.Calendars.DEFAULT_SORT_ORDER);
88                if (cursor == null) {
89                    addItem(items, mActivity.getString(R.string.calendar_info_error), "");
90                } else {
91                    while (cursor.moveToNext()) {
92                        // Process each calendar
93                        int id = cursor.getInt(INDEX_ID);
94                        int eventCount = -1;
95                        int dirtyCount = -1;
96                        String displayName = cursor.getString(INDEX_DISPLAY_NAME);
97
98                        // Compute number of events in the calendar
99                        String where = CalendarContract.Events.CALENDAR_ID + "=" + id;
100                        Cursor eventCursor = mContentResolver.query(
101                                CalendarContract.Events.CONTENT_URI, EVENTS_PROJECTION, where,
102                                null, null);
103                        try {
104                            eventCount = eventCursor.getCount();
105                        } finally {
106                            eventCursor.close();
107                        }
108
109                        // Compute number of dirty events in the calendar
110                        String dirtyWhere = CalendarContract.Events.CALENDAR_ID + "=" + id
111                                + " AND " + CalendarContract.Events.DIRTY + "=1";
112                        Cursor dirtyCursor = mContentResolver.query(
113                                CalendarContract.Events.CONTENT_URI, EVENTS_PROJECTION, dirtyWhere,
114                                null, null);
115                        try {
116                            dirtyCount = dirtyCursor.getCount();
117                        } finally {
118                            dirtyCursor.close();
119                        }
120
121                        // Format the output
122                        String text;
123                        if (dirtyCount == 0) {
124                            text = mActivity.getString(R.string.calendar_info_events,
125                                    eventCount);
126                        } else {
127                            text = mActivity.getString(R.string.calendar_info_events_dirty,
128                                    eventCount, dirtyCount);
129                        }
130
131                        addItem(items, displayName, text);
132                    }
133                }
134            } catch (Exception e) {
135                // Want to catch all exceptions.  The point of this code is to debug
136                // when something bad is happening.
137                addItem(items, mActivity.getString(R.string.calendar_info_error), e.toString());
138            } finally {
139                if (cursor != null) {
140                    cursor.close();
141                }
142            }
143
144            if (items.size() == 0) {
145                addItem(items, mActivity.getString(R.string.calendar_info_no_calendars), "");
146            }
147            return items;
148        }
149
150        /**
151         * Runs on the UI thread to display the debugging info.
152         *
153         * @param items The info items to display.
154         * @see #onPreExecute
155         * @see #doInBackground
156         */
157        @Override
158        protected void onPostExecute(List<Map<String, String>> items) {
159            setProgressBarIndeterminateVisibility(false);
160            ListAdapter adapter = new SimpleAdapter(mActivity, items,
161                    android.R.layout.simple_list_item_2, new String[]{KEY_TITLE, KEY_TEXT},
162                    new int[]{android.R.id.text1, android.R.id.text2});
163
164            // Bind to our new adapter.
165            setListAdapter(adapter);
166        }
167    }
168
169    @Override
170    protected void onCreate(Bundle savedInstanceState) {
171        super.onCreate(savedInstanceState);
172        requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
173        mActivity = this;
174        mContentResolver = getContentResolver();
175        getListView(); // Instantiate, for spinner
176        new FetchInfoTask().execute();
177
178    }
179
180    /**
181     * Adds an item to the item map
182     * @param items The item map to update
183     * @param title Title of the item
184     * @param text Text of the item
185     */
186    protected void addItem(List<Map<String, String>> items, String title, String text) {
187        Map<String, String> itemMap = new HashMap<String, String>();
188        itemMap.put(KEY_TITLE, title);
189        itemMap.put(KEY_TEXT, text);
190        items.add(itemMap);
191    }
192}
193