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 17 package com.android.providers.calendar; 18 19 import android.app.ListActivity; 20 import android.content.ContentResolver; 21 import android.database.Cursor; 22 import android.os.AsyncTask; 23 import android.os.Bundle; 24 import android.os.Handler; 25 import android.provider.Calendar; 26 import android.widget.ListAdapter; 27 import android.widget.SimpleAdapter; 28 import android.view.Window; 29 30 import java.util.ArrayList; 31 import java.util.HashMap; 32 import java.util.List; 33 import 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 */ 41 public class CalendarDebug extends ListActivity { 42 private static final String[] CALENDARS_PROJECTION = new String[]{ 43 Calendar.Calendars._ID, 44 Calendar.Calendars.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 Calendar.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 protected List<Map<String, String>> doInBackground(Void... params) { 79 Cursor cursor = null; 80 // items is the list of items to display in the list. 81 List<Map<String, String>> items = new ArrayList<Map<String, String>>(); 82 try { 83 cursor = mContentResolver.query(Calendar.Calendars.CONTENT_URI, 84 CALENDARS_PROJECTION, 85 null, null /* selectionArgs */, 86 Calendar.Calendars.DEFAULT_SORT_ORDER); 87 if (cursor == null) { 88 addItem(items, mActivity.getString(R.string.calendar_info_error), ""); 89 } else { 90 while (cursor.moveToNext()) { 91 // Process each calendar 92 int id = cursor.getInt(INDEX_ID); 93 int eventCount = -1; 94 int dirtyCount = -1; 95 String displayName = cursor.getString(INDEX_DISPLAY_NAME); 96 97 // Compute number of events in the calendar 98 String where = Calendar.EventsColumns.CALENDAR_ID + "=" + id; 99 Cursor eventCursor = Calendar.Events.query(mContentResolver, 100 EVENTS_PROJECTION, where, null); 101 try { 102 eventCount = eventCursor.getCount(); 103 } finally { 104 eventCursor.close(); 105 } 106 107 // Compute number of dirty events in the calendar 108 String dirtyWhere = Calendar.EventsColumns.CALENDAR_ID + "=" + id 109 + " AND " + Calendar.Events._SYNC_DIRTY + "=1"; 110 Cursor dirtyCursor = Calendar.Events.query(mContentResolver, 111 EVENTS_PROJECTION, dirtyWhere, null); 112 try { 113 dirtyCount = dirtyCursor.getCount(); 114 } finally { 115 dirtyCursor.close(); 116 } 117 118 // Format the output 119 String text; 120 if (dirtyCount == 0) { 121 text = mActivity.getString(R.string.calendar_info_events, 122 eventCount); 123 } else { 124 text = mActivity.getString(R.string.calendar_info_events_dirty, 125 eventCount, dirtyCount); 126 } 127 128 addItem(items, displayName, text); 129 } 130 } 131 } catch (Exception e) { 132 // Want to catch all exceptions. The point of this code is to debug 133 // when something bad is happening. 134 addItem(items, mActivity.getString(R.string.calendar_info_error), e.toString()); 135 } finally { 136 if (cursor != null) { 137 cursor.close(); 138 } 139 } 140 141 if (items.size() == 0) { 142 addItem(items, mActivity.getString(R.string.calendar_info_no_calendars), ""); 143 } 144 return items; 145 } 146 147 /** 148 * Runs on the UI thread to display the debugging info. 149 * 150 * @param items The info items to display. 151 * @see #onPreExecute 152 * @see #doInBackground 153 */ 154 @Override 155 protected void onPostExecute(List<Map<String, String>> items) { 156 setProgressBarIndeterminateVisibility(false); 157 ListAdapter adapter = new SimpleAdapter(mActivity, items, 158 android.R.layout.simple_list_item_2, new String[]{KEY_TITLE, KEY_TEXT}, 159 new int[]{android.R.id.text1, android.R.id.text2}); 160 161 // Bind to our new adapter. 162 setListAdapter(adapter); 163 } 164 } 165 166 protected void onCreate(Bundle savedInstanceState) { 167 super.onCreate(savedInstanceState); 168 requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); 169 mActivity = this; 170 mContentResolver = getContentResolver(); 171 getListView(); // Instantiate, for spinner 172 new FetchInfoTask().execute(); 173 174 } 175 176 /** 177 * Adds an item to the item map 178 * @param items The item map to update 179 * @param title Title of the item 180 * @param text Text of the item 181 */ 182 protected void addItem(List<Map<String, String>> items, String title, String text) { 183 Map<String, String> itemMap = new HashMap<String, String>(); 184 itemMap.put(KEY_TITLE, title); 185 itemMap.put(KEY_TEXT, text); 186 items.add(itemMap); 187 } 188 } 189