/**
* Copyright (c) 2012 Todoroo Inc
*
* See the file "LICENSE" for the full license governing this code.
*/
package com.todoroo.astrid.helper;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.widget.ArrayAdapter;
import com.timsu.astrid.R;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.ContextManager;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.service.ExceptionService;
import com.todoroo.andlib.utility.AndroidUtilities;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.andlib.utility.Preferences;
import com.todoroo.astrid.activity.TaskListFragment;
import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.api.SyncAction;
import com.todoroo.astrid.gtasks.GtasksPreferences;
import com.todoroo.astrid.service.SyncV2Service;
import com.todoroo.astrid.sync.SyncResultCallback;
import com.todoroo.astrid.sync.SyncV2Provider;
/**
* SyncActionHelper is a helper class for encapsulating UI actions
* responsible for performing sync and prompting user to sign up for a new
* sync service.
*
* In order to make this work you need to call register() and unregister() in
* onResume and onPause, respectively.
*
* @author Tim Su <tim@astrid.com>
*
*/
public class SyncActionHelper {
public static final String PREF_LAST_AUTO_SYNC = "taskListLastAutoSync"; //$NON-NLS-1$
private final LinkedHashSet<SyncAction> syncActions = new LinkedHashSet<SyncAction>();
public final SyncResultCallback syncResultCallback;
private final Activity activity;
private final Fragment fragment;
protected SyncActionReceiver syncActionReceiver = new SyncActionReceiver();
@Autowired SyncV2Service syncService;
@Autowired ExceptionService exceptionService;
// --- boilerplate
public SyncActionHelper(Activity activity, Fragment fragment) {
DependencyInjectionService.getInstance().inject(this);
this.activity = activity;
this.fragment = fragment;
syncResultCallback = new ProgressBarSyncResultCallback(activity, fragment,
R.id.progressBar, new Runnable() {
@Override
public void run() {
ContextManager.getContext().sendBroadcast(
new Intent(
AstridApiConstants.BROADCAST_EVENT_REFRESH));
}
});
}
// --- automatic sync logic
public void initiateAutomaticSync() {
long tasksPushedAt = Preferences.getLong(PREF_LAST_AUTO_SYNC, 0);
if (DateUtilities.now() - tasksPushedAt > TaskListFragment.AUTOSYNC_INTERVAL) {
performSyncServiceV2Sync(false);
}
}
// --- sync action receiver logic
/**
* Receiver which receives sync provider intents
*
*/
protected class SyncActionReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent == null
|| !AstridApiConstants.BROADCAST_SEND_SYNC_ACTIONS.equals(intent.getAction()))
return;
try {
Bundle extras = intent.getExtras();
SyncAction syncAction = extras.getParcelable(AstridApiConstants.EXTRAS_RESPONSE);
syncActions.add(syncAction);
} catch (Exception e) {
exceptionService.reportError("receive-sync-action-" + //$NON-NLS-1$
intent.getStringExtra(AstridApiConstants.EXTRAS_ADDON),
e);
}
}
}
public void register() {
activity.registerReceiver(
syncActionReceiver,
new IntentFilter(AstridApiConstants.BROADCAST_SEND_SYNC_ACTIONS));
}
public void unregister() {
AndroidUtilities.tryUnregisterReceiver(activity, syncActionReceiver);
}
public void request() {
syncActions.clear();
Intent broadcastIntent = new Intent(
AstridApiConstants.BROADCAST_REQUEST_SYNC_ACTIONS);
activity.sendOrderedBroadcast(broadcastIntent,
AstridApiConstants.PERMISSION_READ);
}
// --- sync logic
protected void performSyncServiceV2Sync(boolean manual) {
boolean syncOccurred = syncService.synchronizeActiveTasks(manual, syncResultCallback);
if (syncOccurred)
Preferences.setLong(PREF_LAST_AUTO_SYNC, DateUtilities.now());
}
/**
* Intent object with custom label returned by toString.
*
* @author joshuagross <joshua.gross@gmail.com>
*/
protected static class IntentWithLabel extends Intent {
private final String label;
public IntentWithLabel(Intent in, String labelIn) {
super(in);
label = labelIn;
}
@Override
public String toString() {
return label;
}
}
public void performSyncAction() {
List<SyncV2Provider> activeV2Providers = syncService.activeProviders();
int activeSyncs = syncActions.size() + activeV2Providers.size();
if (activeSyncs == 0) {
String desiredCategory = activity.getString(R.string.SyP_label);
// Get a list of all sync plugins and bring user to the prefs pane
// for one of them
Intent queryIntent = new Intent(AstridApiConstants.ACTION_SETTINGS);
PackageManager pm = activity.getPackageManager();
List<ResolveInfo> resolveInfoList = pm.queryIntentActivities(
queryIntent, PackageManager.GET_META_DATA);
int length = resolveInfoList.size();
ArrayList<Intent> syncIntents = new ArrayList<Intent>();
// Loop through a list of all packages (including plugins, addons)
// that have a settings action: filter to sync actions
for (int i = 0; i < length; i++) {
ResolveInfo resolveInfo = resolveInfoList.get(i);
Intent intent = new Intent(AstridApiConstants.ACTION_SETTINGS);
intent.setClassName(resolveInfo.activityInfo.packageName,
resolveInfo.activityInfo.name);
String category = MetadataHelper.resolveActivityCategoryName(
resolveInfo, pm);
if (GtasksPreferences.class.getName().equals(
resolveInfo.activityInfo.name))
continue;
if (resolveInfo.activityInfo.metaData != null) {
Bundle metadata = resolveInfo.activityInfo.metaData;
if (!metadata.getBoolean("syncAction")) //$NON-NLS-1$
continue;
}
if (category.equals(desiredCategory)) {
syncIntents.add(new IntentWithLabel(intent,
resolveInfo.activityInfo.loadLabel(pm).toString()));
}
}
final Intent[] actions = syncIntents.toArray(new Intent[syncIntents.size()]);
DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface click, int which) {
fragment.startActivityForResult(actions[which], TaskListFragment.ACTIVITY_SETTINGS);
}
};
if (actions.length == 1) {
fragment.startActivityForResult(actions[0], TaskListFragment.ACTIVITY_SETTINGS);
} else {
showSyncOptionMenu(actions, listener);
}
} else {
syncService.synchronizeActiveTasks(true, syncResultCallback);
}
}
/**
* Show menu of sync options. This is shown when you're not logged into any
* services, or logged into more than one.
*
* @param <TYPE>
* @param items
* @param listener
*/
private <TYPE> void showSyncOptionMenu(TYPE[] items,
DialogInterface.OnClickListener listener) {
if (items.length == 1) {
listener.onClick(null, 0);
return;
}
ArrayAdapter<TYPE> adapter = new ArrayAdapter<TYPE>(activity,
android.R.layout.simple_spinner_dropdown_item, items);
// show a menu of available options
new AlertDialog.Builder(activity).setTitle(R.string.Sync_now_label).setAdapter(
adapter, listener).show().setOwnerActivity(activity);
}
}