16b858fc6f8afad95a075595016c5c22547924886Erik/* 26b858fc6f8afad95a075595016c5c22547924886Erik * Copyright (C) 2010 The Android Open Source Project 36b858fc6f8afad95a075595016c5c22547924886Erik * 46b858fc6f8afad95a075595016c5c22547924886Erik * Licensed under the Apache License, Version 2.0 (the "License"); 56b858fc6f8afad95a075595016c5c22547924886Erik * you may not use this file except in compliance with the License. 66b858fc6f8afad95a075595016c5c22547924886Erik * You may obtain a copy of the License at 76b858fc6f8afad95a075595016c5c22547924886Erik * 86b858fc6f8afad95a075595016c5c22547924886Erik * http://www.apache.org/licenses/LICENSE-2.0 96b858fc6f8afad95a075595016c5c22547924886Erik * 106b858fc6f8afad95a075595016c5c22547924886Erik * Unless required by applicable law or agreed to in writing, software 116b858fc6f8afad95a075595016c5c22547924886Erik * distributed under the License is distributed on an "AS IS" BASIS, 126b858fc6f8afad95a075595016c5c22547924886Erik * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136b858fc6f8afad95a075595016c5c22547924886Erik * See the License for the specific language governing permissions and 146b858fc6f8afad95a075595016c5c22547924886Erik * limitations under the License. 156b858fc6f8afad95a075595016c5c22547924886Erik */ 166b858fc6f8afad95a075595016c5c22547924886Erik 176b858fc6f8afad95a075595016c5c22547924886Erikpackage com.android.calendar.selectcalendars; 186b858fc6f8afad95a075595016c5c22547924886Erik 196b858fc6f8afad95a075595016c5c22547924886Erikimport android.accounts.Account; 206b858fc6f8afad95a075595016c5c22547924886Erikimport android.app.Activity; 216b858fc6f8afad95a075595016c5c22547924886Erikimport android.app.ListFragment; 226b858fc6f8afad95a075595016c5c22547924886Erikimport android.app.LoaderManager; 236b858fc6f8afad95a075595016c5c22547924886Erikimport android.content.ContentResolver; 246b858fc6f8afad95a075595016c5c22547924886Erikimport android.content.ContentUris; 256b858fc6f8afad95a075595016c5c22547924886Erikimport android.content.ContentValues; 266b858fc6f8afad95a075595016c5c22547924886Erikimport android.content.CursorLoader; 276b858fc6f8afad95a075595016c5c22547924886Erikimport android.content.Intent; 286b858fc6f8afad95a075595016c5c22547924886Erikimport android.content.Loader; 296b858fc6f8afad95a075595016c5c22547924886Erikimport android.content.res.Resources; 30ceae8dba1fd70adeb0b07861f598794ec69d7767Sam Blitzsteinimport android.database.ContentObserver; 316b858fc6f8afad95a075595016c5c22547924886Erikimport android.database.Cursor; 326b858fc6f8afad95a075595016c5c22547924886Erikimport android.net.Uri; 336b858fc6f8afad95a075595016c5c22547924886Erikimport android.os.Bundle; 34ceae8dba1fd70adeb0b07861f598794ec69d7767Sam Blitzsteinimport android.os.Handler; 35a7c0390d9c5dd4ff730de505682687fae5f5ced0RoboErikimport android.provider.CalendarContract; 36a7c0390d9c5dd4ff730de505682687fae5f5ced0RoboErikimport android.provider.CalendarContract.Calendars; 376b858fc6f8afad95a075595016c5c22547924886Erikimport android.view.LayoutInflater; 386b858fc6f8afad95a075595016c5c22547924886Erikimport android.view.View; 396b858fc6f8afad95a075595016c5c22547924886Erikimport android.view.ViewGroup; 406b858fc6f8afad95a075595016c5c22547924886Erikimport android.widget.Button; 41c68cc55b8aaa92f0cc8452ef02b2d015bf8a16feMichael Chanimport android.widget.ListAdapter; 426b858fc6f8afad95a075595016c5c22547924886Erikimport android.widget.TextView; 436b858fc6f8afad95a075595016c5c22547924886Erik 44b546c601b8f0b476e8bc7db649ee0a6ee60ce14cJames Kungimport com.android.calendar.AsyncQueryService; 45b546c601b8f0b476e8bc7db649ee0a6ee60ce14cJames Kungimport com.android.calendar.R; 46b546c601b8f0b476e8bc7db649ee0a6ee60ce14cJames Kungimport com.android.calendar.Utils; 47b546c601b8f0b476e8bc7db649ee0a6ee60ce14cJames Kungimport com.android.calendar.selectcalendars.SelectCalendarsSyncAdapter.CalendarRow; 48b546c601b8f0b476e8bc7db649ee0a6ee60ce14cJames Kung 496b858fc6f8afad95a075595016c5c22547924886Erikimport java.util.HashMap; 506b858fc6f8afad95a075595016c5c22547924886Erik 516b858fc6f8afad95a075595016c5c22547924886Erikpublic class SelectCalendarsSyncFragment extends ListFragment 526b858fc6f8afad95a075595016c5c22547924886Erik implements View.OnClickListener, LoaderManager.LoaderCallbacks<Cursor> { 53b546c601b8f0b476e8bc7db649ee0a6ee60ce14cJames Kung 546b858fc6f8afad95a075595016c5c22547924886Erik private static final String TAG = "SelectCalendarSync"; 556b858fc6f8afad95a075595016c5c22547924886Erik 566b858fc6f8afad95a075595016c5c22547924886Erik private static final String COLLATE_NOCASE = " COLLATE NOCASE"; 570e1e62408b96e1532eb6f6a609ae4c817751aaf3RoboErik private static final String SELECTION = Calendars.ACCOUNT_NAME + "=? AND " 580e1e62408b96e1532eb6f6a609ae4c817751aaf3RoboErik + Calendars.ACCOUNT_TYPE + "=?"; 596b858fc6f8afad95a075595016c5c22547924886Erik // is primary lets us sort the user's main calendar to the top of the list 606b858fc6f8afad95a075595016c5c22547924886Erik private static final String IS_PRIMARY = "\"primary\""; 61ef2add9145f058ea103ade2870a8ba899b9ed1c9RoboErik private static final String SORT_ORDER = IS_PRIMARY + " DESC," + Calendars.CALENDAR_DISPLAY_NAME 626b858fc6f8afad95a075595016c5c22547924886Erik + COLLATE_NOCASE; 636b858fc6f8afad95a075595016c5c22547924886Erik 64cf7fd2b6d1b5af26c4ac422dde1778e2fd6c7ef6Michael Chan private static final String[] PROJECTION = new String[] { 65cf7fd2b6d1b5af26c4ac422dde1778e2fd6c7ef6Michael Chan Calendars._ID, 66cf7fd2b6d1b5af26c4ac422dde1778e2fd6c7ef6Michael Chan Calendars.CALENDAR_DISPLAY_NAME, 67cf7fd2b6d1b5af26c4ac422dde1778e2fd6c7ef6Michael Chan Calendars.CALENDAR_COLOR, 68cf7fd2b6d1b5af26c4ac422dde1778e2fd6c7ef6Michael Chan Calendars.SYNC_EVENTS, 6961388102bec5243dfd4494b8c674cdb7957663a6James Kung Calendars.ACCOUNT_NAME, 7061388102bec5243dfd4494b8c674cdb7957663a6James Kung Calendars.ACCOUNT_TYPE, 71cf7fd2b6d1b5af26c4ac422dde1778e2fd6c7ef6Michael Chan "(" + Calendars.ACCOUNT_NAME + "=" + Calendars.OWNER_ACCOUNT + ") AS " + IS_PRIMARY, }; 726b858fc6f8afad95a075595016c5c22547924886Erik 736b858fc6f8afad95a075595016c5c22547924886Erik private TextView mSyncStatus; 746b858fc6f8afad95a075595016c5c22547924886Erik private Button mAccountsButton; 756b858fc6f8afad95a075595016c5c22547924886Erik private Account mAccount; 763a58ebac8407ba4e3f3843039c5de0611fd80819Isaac Katzenelson private final String[] mArgs = new String[2]; 776b858fc6f8afad95a075595016c5c22547924886Erik private AsyncQueryService mService; 78ceae8dba1fd70adeb0b07861f598794ec69d7767Sam Blitzstein private Handler mHandler = new Handler(); 79ceae8dba1fd70adeb0b07861f598794ec69d7767Sam Blitzstein private ContentObserver mCalendarsObserver = new ContentObserver(mHandler) { 80ceae8dba1fd70adeb0b07861f598794ec69d7767Sam Blitzstein @Override 81ceae8dba1fd70adeb0b07861f598794ec69d7767Sam Blitzstein public void onChange(boolean selfChange) { 82ceae8dba1fd70adeb0b07861f598794ec69d7767Sam Blitzstein // We don't need our own sync changes to trigger refreshes. 83ceae8dba1fd70adeb0b07861f598794ec69d7767Sam Blitzstein if (!selfChange) { 84ceae8dba1fd70adeb0b07861f598794ec69d7767Sam Blitzstein getLoaderManager().initLoader(0, null, SelectCalendarsSyncFragment.this); 85ceae8dba1fd70adeb0b07861f598794ec69d7767Sam Blitzstein } 86ceae8dba1fd70adeb0b07861f598794ec69d7767Sam Blitzstein } 87ceae8dba1fd70adeb0b07861f598794ec69d7767Sam Blitzstein }; 886b858fc6f8afad95a075595016c5c22547924886Erik 896b858fc6f8afad95a075595016c5c22547924886Erik public SelectCalendarsSyncFragment() { 906b858fc6f8afad95a075595016c5c22547924886Erik } 916b858fc6f8afad95a075595016c5c22547924886Erik 926b858fc6f8afad95a075595016c5c22547924886Erik public SelectCalendarsSyncFragment(Bundle bundle) { 930e1e62408b96e1532eb6f6a609ae4c817751aaf3RoboErik mAccount = new Account(bundle.getString(Calendars.ACCOUNT_NAME), 940e1e62408b96e1532eb6f6a609ae4c817751aaf3RoboErik bundle.getString(Calendars.ACCOUNT_TYPE)); 956b858fc6f8afad95a075595016c5c22547924886Erik } 966b858fc6f8afad95a075595016c5c22547924886Erik 976b858fc6f8afad95a075595016c5c22547924886Erik @Override 986b858fc6f8afad95a075595016c5c22547924886Erik public View onCreateView( 996b858fc6f8afad95a075595016c5c22547924886Erik LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 1006b858fc6f8afad95a075595016c5c22547924886Erik View v = inflater.inflate(R.layout.account_calendars, null); 1016b858fc6f8afad95a075595016c5c22547924886Erik mSyncStatus = (TextView) v.findViewById(R.id.account_status); 1026b858fc6f8afad95a075595016c5c22547924886Erik mSyncStatus.setVisibility(View.GONE); 1036b858fc6f8afad95a075595016c5c22547924886Erik 1046b858fc6f8afad95a075595016c5c22547924886Erik mAccountsButton = (Button) v.findViewById(R.id.sync_settings); 1056b858fc6f8afad95a075595016c5c22547924886Erik mAccountsButton.setVisibility(View.GONE); 1066b858fc6f8afad95a075595016c5c22547924886Erik mAccountsButton.setOnClickListener(this); 1076b858fc6f8afad95a075595016c5c22547924886Erik 1086b858fc6f8afad95a075595016c5c22547924886Erik return v; 1096b858fc6f8afad95a075595016c5c22547924886Erik } 1106b858fc6f8afad95a075595016c5c22547924886Erik 1116b858fc6f8afad95a075595016c5c22547924886Erik @Override 1126b858fc6f8afad95a075595016c5c22547924886Erik public void onActivityCreated(Bundle savedInstanceState) { 1136b858fc6f8afad95a075595016c5c22547924886Erik super.onActivityCreated(savedInstanceState); 1146b858fc6f8afad95a075595016c5c22547924886Erik // Give some text to display if there is no data. In a real 1156b858fc6f8afad95a075595016c5c22547924886Erik // application this would come from a resource. 1166b858fc6f8afad95a075595016c5c22547924886Erik setEmptyText(getActivity().getText(R.string.no_syncable_calendars)); 1176b858fc6f8afad95a075595016c5c22547924886Erik // Prepare the loader. Either re-connect with an existing one, 1186b858fc6f8afad95a075595016c5c22547924886Erik // or start a new one. 1196b858fc6f8afad95a075595016c5c22547924886Erik getLoaderManager().initLoader(0, null, this); 1206b858fc6f8afad95a075595016c5c22547924886Erik } 1216b858fc6f8afad95a075595016c5c22547924886Erik 1226b858fc6f8afad95a075595016c5c22547924886Erik @Override 1236b858fc6f8afad95a075595016c5c22547924886Erik public void onResume() { 1246b858fc6f8afad95a075595016c5c22547924886Erik super.onResume(); 1256b858fc6f8afad95a075595016c5c22547924886Erik if (!ContentResolver.getMasterSyncAutomatically() 126a7c0390d9c5dd4ff730de505682687fae5f5ced0RoboErik || !ContentResolver.getSyncAutomatically(mAccount, CalendarContract.AUTHORITY)) { 1276b858fc6f8afad95a075595016c5c22547924886Erik Resources res = getActivity().getResources(); 1286b858fc6f8afad95a075595016c5c22547924886Erik mSyncStatus.setText(res.getString(R.string.acct_not_synced)); 1296b858fc6f8afad95a075595016c5c22547924886Erik mSyncStatus.setVisibility(View.VISIBLE); 1306b858fc6f8afad95a075595016c5c22547924886Erik mAccountsButton.setText(res.getString(R.string.accounts)); 1316b858fc6f8afad95a075595016c5c22547924886Erik mAccountsButton.setVisibility(View.VISIBLE); 1326b858fc6f8afad95a075595016c5c22547924886Erik } else { 1336b858fc6f8afad95a075595016c5c22547924886Erik mSyncStatus.setVisibility(View.GONE); 1346b858fc6f8afad95a075595016c5c22547924886Erik mAccountsButton.setVisibility(View.GONE); 135ceae8dba1fd70adeb0b07861f598794ec69d7767Sam Blitzstein 136ceae8dba1fd70adeb0b07861f598794ec69d7767Sam Blitzstein // Start a background sync to get the list of calendars from the server. 137ceae8dba1fd70adeb0b07861f598794ec69d7767Sam Blitzstein Utils.startCalendarMetafeedSync(mAccount); 138ceae8dba1fd70adeb0b07861f598794ec69d7767Sam Blitzstein getActivity().getContentResolver().registerContentObserver( 139ceae8dba1fd70adeb0b07861f598794ec69d7767Sam Blitzstein Calendars.CONTENT_URI, true, mCalendarsObserver); 140ceae8dba1fd70adeb0b07861f598794ec69d7767Sam Blitzstein } 1416b858fc6f8afad95a075595016c5c22547924886Erik } 1426b858fc6f8afad95a075595016c5c22547924886Erik 1436b858fc6f8afad95a075595016c5c22547924886Erik @Override 1446b858fc6f8afad95a075595016c5c22547924886Erik public void onAttach(Activity activity) { 1456b858fc6f8afad95a075595016c5c22547924886Erik super.onAttach(activity); 1466b858fc6f8afad95a075595016c5c22547924886Erik mService = new AsyncQueryService(activity); 1476b858fc6f8afad95a075595016c5c22547924886Erik 1486b858fc6f8afad95a075595016c5c22547924886Erik Bundle bundle = getArguments(); 1496b858fc6f8afad95a075595016c5c22547924886Erik if (bundle != null && bundle.containsKey(Calendars.ACCOUNT_NAME) 1506b858fc6f8afad95a075595016c5c22547924886Erik && bundle.containsKey(Calendars.ACCOUNT_TYPE)) { 1516b858fc6f8afad95a075595016c5c22547924886Erik mAccount = new Account(bundle.getString(Calendars.ACCOUNT_NAME), 1526b858fc6f8afad95a075595016c5c22547924886Erik bundle.getString(Calendars.ACCOUNT_TYPE)); 1536b858fc6f8afad95a075595016c5c22547924886Erik } 1546b858fc6f8afad95a075595016c5c22547924886Erik } 1556b858fc6f8afad95a075595016c5c22547924886Erik 1566b858fc6f8afad95a075595016c5c22547924886Erik @Override 1576b858fc6f8afad95a075595016c5c22547924886Erik public void onPause() { 158c68cc55b8aaa92f0cc8452ef02b2d015bf8a16feMichael Chan final ListAdapter listAdapter = getListAdapter(); 159c68cc55b8aaa92f0cc8452ef02b2d015bf8a16feMichael Chan if (listAdapter != null) { 160d17780987a421477ae57fe88e48cb2d81c42f517Erik HashMap<Long, CalendarRow> changes = ((SelectCalendarsSyncAdapter) listAdapter) 161c68cc55b8aaa92f0cc8452ef02b2d015bf8a16feMichael Chan .getChanges(); 162c68cc55b8aaa92f0cc8452ef02b2d015bf8a16feMichael Chan if (changes != null && changes.size() > 0) { 163c68cc55b8aaa92f0cc8452ef02b2d015bf8a16feMichael Chan for (CalendarRow row : changes.values()) { 164b331a8217f09c2d48960bc192fc1cda1e6a35faeErik if (row.synced == row.originalSynced) { 165b331a8217f09c2d48960bc192fc1cda1e6a35faeErik continue; 166b331a8217f09c2d48960bc192fc1cda1e6a35faeErik } 167d17780987a421477ae57fe88e48cb2d81c42f517Erik long id = row.id; 168d17780987a421477ae57fe88e48cb2d81c42f517Erik mService.cancelOperation((int) id); 169c68cc55b8aaa92f0cc8452ef02b2d015bf8a16feMichael Chan // Use the full long id in case it makes a difference 170c68cc55b8aaa92f0cc8452ef02b2d015bf8a16feMichael Chan Uri uri = ContentUris.withAppendedId(Calendars.CONTENT_URI, row.id); 171c68cc55b8aaa92f0cc8452ef02b2d015bf8a16feMichael Chan ContentValues values = new ContentValues(); 172c68cc55b8aaa92f0cc8452ef02b2d015bf8a16feMichael Chan // Toggle the current setting 173c68cc55b8aaa92f0cc8452ef02b2d015bf8a16feMichael Chan int synced = row.synced ? 1 : 0; 174c68cc55b8aaa92f0cc8452ef02b2d015bf8a16feMichael Chan values.put(Calendars.SYNC_EVENTS, synced); 175950e8a615f3dcca0b61b2eb8f8de72ecf6825d4bAndy McFadden values.put(Calendars.VISIBLE, synced); 176d17780987a421477ae57fe88e48cb2d81c42f517Erik mService.startUpdate((int) id, null, uri, values, null, null, 0); 177c68cc55b8aaa92f0cc8452ef02b2d015bf8a16feMichael Chan } 178c68cc55b8aaa92f0cc8452ef02b2d015bf8a16feMichael Chan changes.clear(); 1796b858fc6f8afad95a075595016c5c22547924886Erik } 1806b858fc6f8afad95a075595016c5c22547924886Erik } 181ceae8dba1fd70adeb0b07861f598794ec69d7767Sam Blitzstein getActivity().getContentResolver().unregisterContentObserver(mCalendarsObserver); 1826b858fc6f8afad95a075595016c5c22547924886Erik super.onPause(); 1836b858fc6f8afad95a075595016c5c22547924886Erik } 1846b858fc6f8afad95a075595016c5c22547924886Erik 1856b858fc6f8afad95a075595016c5c22547924886Erik @Override 1866b858fc6f8afad95a075595016c5c22547924886Erik public Loader<Cursor> onCreateLoader(int id, Bundle args) { 1876b858fc6f8afad95a075595016c5c22547924886Erik mArgs[0] = mAccount.name; 1886b858fc6f8afad95a075595016c5c22547924886Erik mArgs[1] = mAccount.type; 1896b858fc6f8afad95a075595016c5c22547924886Erik return new CursorLoader( 1906b858fc6f8afad95a075595016c5c22547924886Erik getActivity(), Calendars.CONTENT_URI, PROJECTION, SELECTION, mArgs, SORT_ORDER); 1916b858fc6f8afad95a075595016c5c22547924886Erik } 1926b858fc6f8afad95a075595016c5c22547924886Erik 1936b858fc6f8afad95a075595016c5c22547924886Erik @Override 1946b858fc6f8afad95a075595016c5c22547924886Erik public void onLoadFinished(Loader<Cursor> loader, Cursor data) { 1956b858fc6f8afad95a075595016c5c22547924886Erik SelectCalendarsSyncAdapter adapter = (SelectCalendarsSyncAdapter) getListAdapter(); 1966b858fc6f8afad95a075595016c5c22547924886Erik if (adapter == null) { 197b546c601b8f0b476e8bc7db649ee0a6ee60ce14cJames Kung adapter = new SelectCalendarsSyncAdapter(getActivity(), data, getFragmentManager()); 1983a58ebac8407ba4e3f3843039c5de0611fd80819Isaac Katzenelson setListAdapter(adapter); 1996b858fc6f8afad95a075595016c5c22547924886Erik } else { 2006b858fc6f8afad95a075595016c5c22547924886Erik adapter.changeCursor(data); 2016b858fc6f8afad95a075595016c5c22547924886Erik } 202cf7fd2b6d1b5af26c4ac422dde1778e2fd6c7ef6Michael Chan getListView().setOnItemClickListener(adapter); 2036b858fc6f8afad95a075595016c5c22547924886Erik } 2046b858fc6f8afad95a075595016c5c22547924886Erik 2051d6d7c6fee68b1641ce8664caf5d6832bf6bb618Dianne Hackborn public void onLoaderReset(Loader<Cursor> loader) { 2061d6d7c6fee68b1641ce8664caf5d6832bf6bb618Dianne Hackborn setListAdapter(null); 2071d6d7c6fee68b1641ce8664caf5d6832bf6bb618Dianne Hackborn } 2081d6d7c6fee68b1641ce8664caf5d6832bf6bb618Dianne Hackborn 2096b858fc6f8afad95a075595016c5c22547924886Erik // Called when the Accounts button is pressed. Takes the user to the 2106b858fc6f8afad95a075595016c5c22547924886Erik // Accounts and Sync settings page. 2116b858fc6f8afad95a075595016c5c22547924886Erik @Override 2126b858fc6f8afad95a075595016c5c22547924886Erik public void onClick(View v) { 2136b858fc6f8afad95a075595016c5c22547924886Erik Intent intent = new Intent(); 2146b858fc6f8afad95a075595016c5c22547924886Erik intent.setAction("android.settings.SYNC_SETTINGS"); 2156b858fc6f8afad95a075595016c5c22547924886Erik getActivity().startActivity(intent); 2166b858fc6f8afad95a075595016c5c22547924886Erik } 2176b858fc6f8afad95a075595016c5c22547924886Erik} 218