/* * * * Copyright (C) 2014 Open Whisper Systems * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * / */ package org.anhonesteffort.flock; import android.accounts.Account; import android.accounts.AccountManager; import android.app.Activity; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.os.AsyncTask; import android.os.Bundle; import android.os.RemoteException; import android.text.TextUtils; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.CompoundButton; import android.widget.EditText; import android.widget.ListView; import android.widget.Toast; import com.chiralcode.colorpicker.ColorPicker; import org.anhonesteffort.flock.util.guava.Optional; import org.anhonesteffort.flock.sync.calendar.LocalCalendarStore; import org.anhonesteffort.flock.sync.calendar.LocalEventCollection; import java.util.LinkedList; import java.util.List; /** * Programmer: rhodey */ public class ImportCalendarsFragment extends AccountAndKeyRequiredFragment implements CompoundButton.OnCheckedChangeListener { private static final String TAG = "org.anhonesteffort.flock.ImportCalendarsFragment"; private AsyncTask asyncTask; private ListView localCalendarListView; private SetupActivity setupActivity; private AlertDialog alertDialog; private List<LocalEventCollection> selectedCalendars; private List<CalendarForCopy> calendarsForCopyService = new LinkedList<CalendarForCopy>(); private boolean list_is_initializing = false; private int indexOfCalendarToPrompt = -1; @Override public void onAttach(Activity activity) { super.onAttach(activity); if (activity instanceof SetupActivity) this.setupActivity = (SetupActivity) activity; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View fragmentView = inflater.inflate(R.layout.fragment_simple_list, container, false); if (!accountAndKeyAvailable()) return fragmentView; initButtons(); return fragmentView; } @Override public void onResume() { super.onResume(); if (!accountAndKeyAvailable()) return ; initializeList(); } @Override public void onPause() { super.onPause(); if (alertDialog != null) alertDialog.dismiss(); if (asyncTask != null && !asyncTask.isCancelled()) asyncTask.cancel(true); } private void handleBackgroundImportStarted() { Log.d(TAG, "handleBackgroundImportStarted()"); if (selectedCalendars.size() > 0) { String toastMessage = getString(R.string.started_background_import_of_calendars, selectedCalendars.size()); Toast.makeText(getActivity(), toastMessage, Toast.LENGTH_SHORT).show(); } if (setupActivity != null) setupActivity.updateFragmentUsingState(SetupActivity.STATE_SELECT_REMOTE_ADDRESSBOOK); else getActivity().finish(); } private void handlePromptComplete(LocalEventCollection importCalendar, String calendarName, int calendarColor) { try { calendarsForCopyService.add( new CalendarForCopy( importCalendar.getAccount(), importCalendar.getLocalId(), calendarName, calendarColor, importCalendar.getComponentIds().size() ) ); indexOfCalendarToPrompt++; handlePromptForNextCalendarNameAndColors(); } catch (RemoteException e) { indexOfCalendarToPrompt = -1; selectedCalendars.clear(); initializeList(); } } private void handlePromptForCalendar(final LocalEventCollection importCalendar) throws RemoteException { LayoutInflater inflater = getActivity().getLayoutInflater(); View view = inflater.inflate(R.layout.dialog_calendar_edit, null); final EditText displayNameEdit = (EditText ) view.findViewById(R.id.dialog_display_name); final ColorPicker colorPicker = (ColorPicker) view.findViewById(R.id.dialog_calendar_color); AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); Optional<String> displayName = importCalendar.getDisplayName(); if (displayName.isPresent()) displayNameEdit.setText(displayName.get()); Optional<Integer> color = importCalendar.getColor(); if (color.isPresent()) colorPicker.setColor(color.get()); builder.setView(view).setTitle(R.string.title_calendar_properties); builder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int id) { if (TextUtils.isEmpty(displayNameEdit.getText().toString())) { Toast.makeText(getActivity(), R.string.display_name_cannot_be_empty, Toast.LENGTH_LONG).show(); } else { handlePromptComplete(importCalendar, displayNameEdit.getText().toString(), colorPicker.getColor()); } } }); builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { indexOfCalendarToPrompt = -1; selectedCalendars.clear(); initializeList(); } }); builder.setOnCancelListener(new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { indexOfCalendarToPrompt = -1; selectedCalendars.clear(); initializeList(); } }); alertDialog = builder.show(); } private void handlePromptForNextCalendarNameAndColors() { Log.d(TAG, "handlePromptForNextCalendarNameAndColors()"); if (indexOfCalendarToPrompt == -1) indexOfCalendarToPrompt = 0; try { if (indexOfCalendarToPrompt < selectedCalendars.size()) handlePromptForCalendar(selectedCalendars.get(indexOfCalendarToPrompt)); else if (calendarsForCopyService.size() > 0) { handleStartBackgroundCopyService(calendarsForCopyService); handleBackgroundImportStarted(); } } catch (RemoteException e) { indexOfCalendarToPrompt = -1; selectedCalendars.clear(); initializeList(); } } private void initButtons() { Button actionButton; if (setupActivity != null) { actionButton = (Button) getActivity().findViewById(R.id.button_next); actionButton.setText(R.string.skip); } else { actionButton = (Button) getActivity().findViewById(R.id.button_action); actionButton.setText(R.string.cancel); } actionButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (selectedCalendars.size() > 0) handlePromptForNextCalendarNameAndColors(); else handleBackgroundImportStarted(); } }); } private void initializeList() { Log.d(TAG, "initializeList()"); if (list_is_initializing) return; selectedCalendars = new LinkedList<LocalEventCollection>(); list_is_initializing = true; calendarsForCopyService = new LinkedList<CalendarForCopy>(); indexOfCalendarToPrompt = -1; asyncTask = new RetrieveCalendarsTask().execute(); } @Override public void onCheckedChanged(CompoundButton compoundButton, boolean b) { Button actionButton; if (setupActivity != null) actionButton = (Button) getActivity().findViewById(R.id.button_next); else actionButton = (Button) getActivity().findViewById(R.id.button_action); if (selectedCalendars.size() > 0 && setupActivity != null) actionButton.setText(R.string.next); else if (selectedCalendars.size() > 0 && setupActivity == null) actionButton.setText(R.string.button_import); else if (setupActivity != null) actionButton.setText(R.string.skip); else actionButton.setText(R.string.cancel); } private void handleLocalCalendarsRetrieved(List<LocalEventCollection> localCalendars) { Log.d(TAG, " handleLocalCalendarsRetrieved()"); LocalEventCollection[] localCalendarArray = new LocalEventCollection[localCalendars.size()]; for (int i = 0; i < localCalendars.size(); i++) localCalendarArray[i] = localCalendars.get(i); LocalCalendarListAdapter listAdapter = new LocalCalendarListAdapter(getActivity().getBaseContext(), localCalendarArray, selectedCalendars, this); localCalendarListView = (ListView)getView().findViewById(R.id.list); localCalendarListView.setAdapter(listAdapter); list_is_initializing = false; } private void handleStartBackgroundCopyService(final List<CalendarForCopy> copyCalendars) { final Context hackContext = getActivity().getApplicationContext(); new AsyncTask<String, Void, Bundle>() { @Override protected Bundle doInBackground(String... params) { Bundle result = new Bundle(); Intent copyService = new Intent(hackContext, CalendarCopyService.class); for (CalendarForCopy copyCalendar : copyCalendars) { copyService.setAction(CalendarCopyService.ACTION_QUEUE_ACCOUNT_FOR_COPY); copyService.putExtra(CalendarCopyService.KEY_FROM_ACCOUNT, copyCalendar.fromAccount); copyService.putExtra(CalendarCopyService.KEY_TO_ACCOUNT, account.getOsAccount()); copyService.putExtra(CalendarCopyService.KEY_CALENDAR_ID, copyCalendar.calendarId); copyService.putExtra(CalendarCopyService.KEY_CALENDAR_NAME, copyCalendar.calendarName); copyService.putExtra(CalendarCopyService.KEY_CALENDAR_COLOR, copyCalendar.calendarColor); copyService.putExtra(CalendarCopyService.KEY_EVENT_COUNT, copyCalendar.eventCount); hackContext.startService(copyService); } copyService.setAction(CalendarCopyService.ACTION_START_COPY); hackContext.startService(copyService); result.putInt(ErrorToaster.KEY_STATUS_CODE, ErrorToaster.CODE_SUCCESS); return result; } @Override protected void onPostExecute(Bundle result) { Log.d(TAG, "STATUS: " + result.getInt(ErrorToaster.KEY_STATUS_CODE)); if (result.getInt(ErrorToaster.KEY_STATUS_CODE) != ErrorToaster.CODE_SUCCESS) ErrorToaster.handleDisplayToastBundledError(hackContext, result); } }.execute(); } private class RetrieveCalendarsTask extends AsyncTask<Void, Void, Bundle> { private List<LocalEventCollection> localCalendars; @Override protected void onPreExecute() { Log.d(TAG, "RetrieveCalendarsTask()"); getActivity().setProgressBarIndeterminateVisibility(true); getActivity().setProgressBarVisibility(true); } protected List<LocalEventCollection> getLocalCalendars(List<Account> localAccounts) throws RemoteException { List<LocalEventCollection> collections = new LinkedList<LocalEventCollection>(); for (Account localAccount : localAccounts) { LocalCalendarStore localStore = new LocalCalendarStore(getActivity(), localAccount); collections.addAll(localStore.getCollectionsIgnoreSync()); } return collections; } protected List<Account> getOtherAccounts() { List<Account> accounts = new LinkedList<Account>(); for (Account osAccount : AccountManager.get(getActivity()).getAccounts()) { if (!osAccount.name.equals(account.getOsAccount().name) && !osAccount.type.equals(account.getOsAccount().type)) { accounts.add(osAccount); } } return accounts; } @Override protected Bundle doInBackground(Void... params) { Bundle result = new Bundle(); List<Account> otherAccounts = getOtherAccounts(); try { localCalendars = getLocalCalendars(otherAccounts); result.putInt(ErrorToaster.KEY_STATUS_CODE, ErrorToaster.CODE_SUCCESS); } catch (RemoteException e) { ErrorToaster.handleBundleError(e, result); } return result; } @Override protected void onPostExecute(Bundle result) { Log.d(TAG, "STATUS: " + result.getInt(ErrorToaster.KEY_STATUS_CODE)); getActivity().setProgressBarIndeterminateVisibility(false); getActivity().setProgressBarVisibility(false); if (result.getInt(ErrorToaster.KEY_STATUS_CODE) == ErrorToaster.CODE_SUCCESS) handleLocalCalendarsRetrieved(localCalendars); else ErrorToaster.handleDisplayToastBundledError(getActivity(), result); } } private static class CalendarForCopy { public Account fromAccount; public long calendarId; public String calendarName; public int calendarColor; public int eventCount; public CalendarForCopy(Account fromAccount, long calendarId, String calendarName, int calendarColor, int eventCount) { this.fromAccount = fromAccount; this.calendarId = calendarId; this.calendarName = calendarName; this.calendarColor = calendarColor; this.eventCount = eventCount; } } }