1/* 2 * Copyright (C) 2010 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.calendar.selectcalendars; 18 19import com.android.calendar.AsyncQueryService; 20import com.android.calendar.R; 21import com.android.calendar.selectcalendars.SelectCalendarsSyncAdapter.CalendarRow; 22 23import android.accounts.Account; 24import android.app.Activity; 25import android.app.ListFragment; 26import android.app.LoaderManager; 27import android.content.ContentResolver; 28import android.content.ContentUris; 29import android.content.ContentValues; 30import android.content.CursorLoader; 31import android.content.Intent; 32import android.content.Loader; 33import android.content.res.Resources; 34import android.database.Cursor; 35import android.net.Uri; 36import android.os.Bundle; 37import android.provider.CalendarContract; 38import android.provider.CalendarContract.Calendars; 39import android.view.LayoutInflater; 40import android.view.View; 41import android.view.ViewGroup; 42import android.widget.Button; 43import android.widget.ListAdapter; 44import android.widget.TextView; 45 46import java.util.HashMap; 47 48public class SelectCalendarsSyncFragment extends ListFragment 49 implements View.OnClickListener, LoaderManager.LoaderCallbacks<Cursor> { 50 private static final String TAG = "SelectCalendarSync"; 51 52 private static final String COLLATE_NOCASE = " COLLATE NOCASE"; 53 private static final String SELECTION = Calendars.ACCOUNT_NAME + "=? AND " 54 + Calendars.ACCOUNT_TYPE + "=?"; 55 // is primary lets us sort the user's main calendar to the top of the list 56 private static final String IS_PRIMARY = "\"primary\""; 57 private static final String SORT_ORDER = IS_PRIMARY + " DESC," + Calendars.CALENDAR_DISPLAY_NAME 58 + COLLATE_NOCASE; 59 60 private static final String[] PROJECTION = new String[] { 61 Calendars._ID, 62 Calendars.CALENDAR_DISPLAY_NAME, 63 Calendars.CALENDAR_COLOR, 64 Calendars.SYNC_EVENTS, 65 "(" + Calendars.ACCOUNT_NAME + "=" + Calendars.OWNER_ACCOUNT + ") AS " + IS_PRIMARY, }; 66 67 private TextView mSyncStatus; 68 private Button mAccountsButton; 69 private Account mAccount; 70 private final String[] mArgs = new String[2]; 71 private AsyncQueryService mService; 72 73 public SelectCalendarsSyncFragment() { 74 } 75 76 public SelectCalendarsSyncFragment(Bundle bundle) { 77 mAccount = new Account(bundle.getString(Calendars.ACCOUNT_NAME), 78 bundle.getString(Calendars.ACCOUNT_TYPE)); 79 } 80 81 @Override 82 public View onCreateView( 83 LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 84 View v = inflater.inflate(R.layout.account_calendars, null); 85 mSyncStatus = (TextView) v.findViewById(R.id.account_status); 86 mSyncStatus.setVisibility(View.GONE); 87 88 mAccountsButton = (Button) v.findViewById(R.id.sync_settings); 89 mAccountsButton.setVisibility(View.GONE); 90 mAccountsButton.setOnClickListener(this); 91 92 return v; 93 } 94 95 @Override 96 public void onActivityCreated(Bundle savedInstanceState) { 97 super.onActivityCreated(savedInstanceState); 98 // Give some text to display if there is no data. In a real 99 // application this would come from a resource. 100 setEmptyText(getActivity().getText(R.string.no_syncable_calendars)); 101 // Prepare the loader. Either re-connect with an existing one, 102 // or start a new one. 103 getLoaderManager().initLoader(0, null, this); 104 } 105 106 @Override 107 public void onResume() { 108 super.onResume(); 109 if (!ContentResolver.getMasterSyncAutomatically() 110 || !ContentResolver.getSyncAutomatically(mAccount, CalendarContract.AUTHORITY)) { 111 Resources res = getActivity().getResources(); 112 mSyncStatus.setText(res.getString(R.string.acct_not_synced)); 113 mSyncStatus.setVisibility(View.VISIBLE); 114 mAccountsButton.setText(res.getString(R.string.accounts)); 115 mAccountsButton.setVisibility(View.VISIBLE); 116 } else { 117 mSyncStatus.setVisibility(View.GONE); 118 mAccountsButton.setVisibility(View.GONE); 119 } 120 } 121 122 @Override 123 public void onAttach(Activity activity) { 124 super.onAttach(activity); 125 mService = new AsyncQueryService(activity); 126 127 Bundle bundle = getArguments(); 128 if (bundle != null && bundle.containsKey(Calendars.ACCOUNT_NAME) 129 && bundle.containsKey(Calendars.ACCOUNT_TYPE)) { 130 mAccount = new Account(bundle.getString(Calendars.ACCOUNT_NAME), 131 bundle.getString(Calendars.ACCOUNT_TYPE)); 132 } 133 } 134 135 @Override 136 public void onPause() { 137 final ListAdapter listAdapter = getListAdapter(); 138 if (listAdapter != null) { 139 HashMap<Long, CalendarRow> changes = ((SelectCalendarsSyncAdapter) listAdapter) 140 .getChanges(); 141 if (changes != null && changes.size() > 0) { 142 for (CalendarRow row : changes.values()) { 143 if (row.synced == row.originalSynced) { 144 continue; 145 } 146 long id = row.id; 147 mService.cancelOperation((int) id); 148 // Use the full long id in case it makes a difference 149 Uri uri = ContentUris.withAppendedId(Calendars.CONTENT_URI, row.id); 150 ContentValues values = new ContentValues(); 151 // Toggle the current setting 152 int synced = row.synced ? 1 : 0; 153 values.put(Calendars.SYNC_EVENTS, synced); 154 values.put(Calendars.VISIBLE, synced); 155 mService.startUpdate((int) id, null, uri, values, null, null, 0); 156 } 157 changes.clear(); 158 } 159 } 160 super.onPause(); 161 } 162 163 @Override 164 public Loader<Cursor> onCreateLoader(int id, Bundle args) { 165 mArgs[0] = mAccount.name; 166 mArgs[1] = mAccount.type; 167 return new CursorLoader( 168 getActivity(), Calendars.CONTENT_URI, PROJECTION, SELECTION, mArgs, SORT_ORDER); 169 } 170 171 @Override 172 public void onLoadFinished(Loader<Cursor> loader, Cursor data) { 173 SelectCalendarsSyncAdapter adapter = (SelectCalendarsSyncAdapter) getListAdapter(); 174 if (adapter == null) { 175 adapter = new SelectCalendarsSyncAdapter(getActivity(), data); 176 setListAdapter(adapter); 177 } else { 178 adapter.changeCursor(data); 179 } 180 getListView().setOnItemClickListener(adapter); 181 } 182 183 public void onLoaderReset(Loader<Cursor> loader) { 184 setListAdapter(null); 185 } 186 187 // Called when the Accounts button is pressed. Takes the user to the 188 // Accounts and Sync settings page. 189 @Override 190 public void onClick(View v) { 191 Intent intent = new Intent(); 192 intent.setAction("android.settings.SYNC_SETTINGS"); 193 getActivity().startActivity(intent); 194 } 195} 196