RTM Synchronization: got authentication working. now to do the synchronize bit.

pull/14/head
Tim Su 16 years ago
parent 79be2aed86
commit db20f92769

@ -1,16 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.timsu.astrid"
android:versionCode="55"
android:versionName="1.11.10">
android:versionCode="56"
android:versionName="1.12">
<meta-data android:name="com.a0soft.gphone.aTrackDog.webURL"
android:value="http://www.weloveastrid.com" />
<meta-data android:name="com.a0soft.gphone.aTrackDog.testVersion"
android:value="48" />
android:value="56" />
<uses-permission android:name="android.permission.VIBRATE"/>
<!-- uses-permission android:name="android.permission.INTERNET"/-->
<uses-permission android:name="android.permission.INTERNET"/>
<application android:icon="@drawable/icon" android:label="@string/app_name">
@ -34,6 +34,8 @@
<activity android:name=".activities.TagList"/>
<activity android:name=".activities.EditPreferences"/>
<activity android:name=".activities.SyncPreferences"/>
<!-- Receivers -->

@ -88,6 +88,7 @@
<string name="taskList_menu_tags">Tags</string>
<string name="taskList_menu_filters">Display</string>
<string name="taskList_menu_more">More</string>
<string name="taskList_menu_sync">Synchronization</string>
<string name="taskList_menu_settings">Settings</string>
<string name="taskList_menu_help">Help</string>
@ -182,7 +183,7 @@ If you don\'t want to see the new task right after you complete the old one, you
<string name="ago_suffix"> Ago</string>
<string name="progress_dialog">% of Task Finished</string>
<!-- Tag List -->
<!-- Tag List -->
<skip />
<string name="tagList_titlePrefix">Astrid: Tag View: </string>
<string name="tagList_context_create">Create Task With Tag</string>
@ -193,12 +194,26 @@ If you don\'t want to see the new task right after you complete the old one, you
<string name="tagList_menu_sortAlpha">Sort A-Z</string>
<string name="tagList_menu_sortSize">Sort by Size</string>
<!-- Dialog Boxes -->
<!-- Synchronization -->
<skip />
<string name="p_sync_rtm">sync_rtm</string>
<string name="sync_pref_group">Synchronization Services</string>
<string name="sync_rtm_title">Remember The Milk</string>
<string name="sync_rtm_desc">http://www.rememberthemilk.com</string>
<string name="sync_error">Sync Error!</string>
<string name="sync_auth_request">
In order to synchronize, please log in to your %s account and authorize Astrid to read your data.
\n\n
When finished, restart Astrid.
</string>
<!-- Dialog Boxes -->
<skip />
<string name="information_title">Information</string>
<string name="question_title">Question</string>
<string name="notify_yes">Let's do it!</string>
<string name="notify_yes">Let\'s do it!</string>
<string name="notify_snooze">Snooze!</string>
<string name="notify_no">No, quit.</string>
<string name="notify_snooze_title">Hours/minutes to snooze?</string>

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory
android:title="@string/sync_pref_group">
<CheckBoxPreference
android:key="@string/p_sync_rtm"
android:title="@string/sync_rtm_title"
android:summary="@string/sync_rtm_desc" />
</PreferenceCategory>
</PreferenceScreen>

@ -0,0 +1,15 @@
package com.timsu.astrid.activities;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import com.timsu.astrid.R;
public class SyncPreferences extends PreferenceActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.sync_preferences);
}
}

@ -57,6 +57,7 @@ import com.timsu.astrid.data.tag.TagModelForView;
import com.timsu.astrid.data.task.TaskController;
import com.timsu.astrid.data.task.TaskIdentifier;
import com.timsu.astrid.data.task.TaskModelForList;
import com.timsu.astrid.sync.Synchronizer;
import com.timsu.astrid.utilities.Constants;
import com.timsu.astrid.utilities.StartupReceiver;
@ -77,6 +78,7 @@ public class TaskList extends Activity {
private static final int ACTIVITY_VIEW = 1;
private static final int ACTIVITY_EDIT = 2;
private static final int ACTIVITY_TAGS = 3;
private static final int ACTIVITY_SYNCHRONIZE = 4;
// menu codes
private static final int INSERT_ID = Menu.FIRST;
@ -84,8 +86,9 @@ public class TaskList extends Activity {
private static final int TAGS_ID = Menu.FIRST + 2;
private static final int MORE_ID = Menu.FIRST + 3;
private static final int OPTIONS_SETTINGS_ID = Menu.FIRST + 10;
private static final int OPTIONS_HELP_ID = Menu.FIRST + 11;
private static final int OPTIONS_SYNC_ID = Menu.FIRST + 10;
private static final int OPTIONS_SETTINGS_ID = Menu.FIRST + 11;
private static final int OPTIONS_HELP_ID = Menu.FIRST + 12;
private static final int CONTEXT_FILTER_HIDDEN = Menu.FIRST + 20;
private static final int CONTEXT_FILTER_DONE = Menu.FIRST + 21;
@ -163,7 +166,7 @@ public class TaskList extends Activity {
});
fillData();
// TODO Synchronizer.authenticate(this);
Synchronizer.synchronize(this);
gestureDetector = new GestureDetector(new TaskListGestureDetector());
gestureTouchListener = new View.OnTouchListener() {
@ -238,14 +241,16 @@ public class TaskList extends Activity {
public boolean onCreateMoreOptionsMenu(Menu menu) {
MenuItem item;
item = menu.add(Menu.NONE, OPTIONS_SYNC_ID, Menu.NONE,
R.string.taskList_menu_sync);
item.setAlphabeticShortcut('s');
item = menu.add(Menu.NONE, OPTIONS_SETTINGS_ID, Menu.NONE,
R.string.taskList_menu_settings);
item.setIcon(android.R.drawable.ic_menu_preferences);
item.setAlphabeticShortcut('p');
item = menu.add(Menu.NONE, OPTIONS_HELP_ID, Menu.NONE,
R.string.taskList_menu_help);
item.setIcon(android.R.drawable.ic_menu_help);
item.setAlphabeticShortcut('h');
return true;
@ -520,9 +525,10 @@ public class TaskList extends Activity {
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
/** Handle case where authentication just happened */
if(resultCode == Constants.RESULT_SYNCHRONIZE) {
// TODO Synchronizer.performSync(this, true);
/** Handle synchronization callbacks */
if(requestCode == ACTIVITY_SYNCHRONIZE) {
Synchronizer.synchronizerStatusUpdated(this);
Synchronizer.synchronize(this);
}
if(requestCode == ACTIVITY_TAGS && resultCode == RESULT_CANCELED)
@ -601,6 +607,10 @@ public class TaskList extends Activity {
layout.showContextMenu();
return true;
case OPTIONS_SYNC_ID:
startActivityForResult(new Intent(this, SyncPreferences.class),
ACTIVITY_SYNCHRONIZE);
return true;
case OPTIONS_SETTINGS_ID:
startActivity(new Intent(this, EditPreferences.class));
return true;

@ -0,0 +1,119 @@
package com.timsu.astrid.sync;
import java.util.Map.Entry;
import android.app.Activity;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Resources;
import android.net.Uri;
import android.util.Log;
import com.mdt.rtm.ApplicationInfo;
import com.mdt.rtm.ServiceImpl;
import com.mdt.rtm.data.RtmList;
import com.mdt.rtm.data.RtmLists;
import com.mdt.rtm.data.RtmAuth.Perms;
import com.timsu.astrid.R;
import com.timsu.astrid.utilities.DialogUtilities;
import com.timsu.astrid.utilities.Preferences;
public class RTMSyncService implements SynchronizationService {
private ServiceImpl rtmService = null;
private int id;
public RTMSyncService(int id) {
this.id = id;
}
@Override
public void synchronize(Activity activity) {
authenticate(activity);
}
@Override
public void synchronizationDisabled(Activity activity) {
Preferences.setSyncRTMToken(activity, null);
}
/** Perform authentication with RTM. Will open the SyncBrowser if necessary */
private void authenticate(final Activity activity) {
try {
String apiKey = "bd9883b3384a21ead17501da38bb1e68";
String sharedSecret = "a19b2a020345219b";
String appName = null;
String authToken = Preferences.getSyncRTMToken(activity);
// check if our auth token works
if(authToken != null) {
rtmService = new ServiceImpl(new ApplicationInfo(
apiKey, sharedSecret, appName, authToken));
if(!rtmService.isServiceAuthorized()) // re-do login
authToken = null;
}
if(authToken == null) {
// try completing the authorization.
if(rtmService != null) {
try {
String token = rtmService.completeAuthorization();
Log.w("astrid", "got RTM token: " + token);
Preferences.setSyncRTMToken(activity, token);
performSync(activity);
return;
} catch (Exception e) {
// didn't work. do the process again.
}
}
rtmService = new ServiceImpl(new ApplicationInfo(
apiKey, sharedSecret, appName));
final String url = rtmService.beginAuthorization(Perms.delete);
Resources r = activity.getResources();
DialogUtilities.okCancelDialog(activity,
r.getString(R.string.sync_auth_request, "RTM"),
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(Intent.ACTION_VIEW,
Uri.parse(url));
activity.startActivity(intent);
}
}, null);
} else {
performSync(activity);
}
} catch (Exception e) {
Synchronizer.showError(activity, e);
}
}
private void performSync(Activity activity) {
try {
Log.i("astrid", "isAuthorized: " + rtmService.isServiceAuthorized());
RtmLists lists = rtmService.lists_getList();
for(Entry<String, RtmList> list : lists.getLists().entrySet()) {
Log.i("astrid", "look, " + list.getKey());
}
// fetch tasks that've changed since last sync
// grab my own list of tasks that have changed since last sync
// if we find a conflict... remember and ignore
// update tasks that have changed
} catch (Exception e) {
Synchronizer.showError(activity, e);
}
}
}

@ -0,0 +1,17 @@
package com.timsu.astrid.sync;
import android.app.Activity;
/** A service that synchronizes with Astrid
*
* @author timsu
*
*/
public interface SynchronizationService {
/** Synchronize with the service */
void synchronize(Activity activity);
/** Called when synchronization with this service is turned off */
void synchronizationDisabled(Activity activity);
}

@ -1,71 +1,62 @@
package com.timsu.astrid.sync;
import java.util.Map.Entry;
import java.util.HashMap;
import java.util.Map;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.Resources;
import android.util.Log;
import com.mdt.rtm.ApplicationInfo;
import com.mdt.rtm.ServiceImpl;
import com.mdt.rtm.data.RtmList;
import com.mdt.rtm.data.RtmLists;
import com.mdt.rtm.data.RtmAuth.Perms;
import com.timsu.astrid.utilities.Constants;
import com.timsu.astrid.R;
import com.timsu.astrid.utilities.DialogUtilities;
import com.timsu.astrid.utilities.Preferences;
public class Synchronizer {
private static ServiceImpl rtmService = null;
/* Synchronization Service ID's */
private static final int SYNC_ID_RTM = 1;
public static void authenticate(Activity activity) {
try {
String apiKey = "127d19adab1a7b6922d8dfda3ef09645";
String sharedSecret = "503816890a685753";
String appName = null;
String authToken = null;
// check if our auth token works
if(authToken != null) {
rtmService = new ServiceImpl(new ApplicationInfo(
apiKey, sharedSecret, appName, authToken));
if(!rtmService.isServiceAuthorized()) // re-do login
authToken = null;
}
/** Service map */
private static Map<Integer, SynchronizationService> services =
new HashMap<Integer, SynchronizationService>();
static {
services.put(SYNC_ID_RTM, new RTMSyncService(SYNC_ID_RTM));
}
if(authToken == null) {
rtmService = new ServiceImpl(new ApplicationInfo(
apiKey, sharedSecret, appName));
String url = rtmService.beginAuthorization(Perms.delete);
// --- public interface
Intent browserIntent = new Intent(Intent.ACTION_VIEW,
Uri.parse(url));
activity.startActivityForResult(browserIntent,
Constants.RESULT_SYNCHRONIZE);
} else {
performSync(activity, false);
}
/** Synchronize all activated sync services */
public static void synchronize(Activity activity) {
// RTM sync
if(Preferences.shouldSyncRTM(activity)) {
services.get(SYNC_ID_RTM).synchronize(activity);
}
}
} catch (Exception e) {
Log.e("astrid", "error parsing", e); // TODO dialog box
/** Clears tokens if services are disabled */
public static void synchronizerStatusUpdated(Activity activity) {
if(!Preferences.shouldSyncRTM(activity)) {
services.get(SYNC_ID_RTM).synchronizationDisabled(activity);
}
}
public static void performSync(Activity activity, boolean justLoggedIn) {
try {
// store token
if(justLoggedIn) {
String token = rtmService.completeAuthorization();
Log.w("astrid", "LOOK A TOKEN " + token);
}
// --- package utilities
/** Utility class for showing synchronization errors */
static void showError(Context context, Throwable e) {
Log.e("astrid", "Synchronization Error", e);
System.out.println("isAuthorized: " + rtmService.isServiceAuthorized());
RtmLists lists = rtmService.lists_getList();
for(Entry<String, RtmList> list : lists.getLists().entrySet()) {
Log.i("astrid", "look, " + list.getKey());
Resources r = context.getResources();
DialogUtilities.okDialog(context,
r.getString(R.string.sync_error) + " " +
e.getLocalizedMessage(), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// do nothing?
}
} catch (Exception e) {
Log.e("astrid", "error parsing", e); // TODO dialog box
}
});
}
}

@ -17,4 +17,16 @@ public class DialogUtilities {
.setPositiveButton(android.R.string.ok, okListener)
.show();
}
public static void okCancelDialog(Context context, String text,
DialogInterface.OnClickListener okListener,
DialogInterface.OnClickListener cancelListener) {
new AlertDialog.Builder(context)
.setTitle(R.string.information_title)
.setMessage(text)
.setIcon(android.R.drawable.ic_dialog_alert)
.setPositiveButton(android.R.string.ok, okListener)
.setNegativeButton(android.R.string.cancel, cancelListener)
.show();
}
}

@ -14,6 +14,7 @@ public class Preferences {
// pref keys
private static final String P_CURRENT_VERSION = "cv";
private static final String P_SHOW_REPEAT_HELP = "repeathelp";
private static final String P_SYNC_RTM_TOKEN = "rtmtoken";
// default values
private static final boolean DEFAULT_PERSISTENCE_MODE = true;
@ -117,8 +118,35 @@ public class Preferences {
return getIntegerValue(context, R.string.p_notif_defaultRemind);
}
// --- synchronization preferences
/** RTM authentication token, or null if doesn't exist */
public static String getSyncRTMToken(Context context) {
return getPrefs(context).getString(P_SYNC_RTM_TOKEN, null);
}
/** Sets the RTM authentication token. Set to null to clear. */
public static void setSyncRTMToken(Context context, String setting) {
Editor editor = getPrefs(context).edit();
editor.putString(P_SYNC_RTM_TOKEN, setting);
editor.commit();
}
/** Should sync with RTM? */
public static boolean shouldSyncRTM(Context context) {
Resources r = context.getResources();
return getPrefs(context).getBoolean(r.getString(
R.string.p_sync_rtm), false);
}
// --- helper methods
private static void clearPref(Context context, String key) {
Editor editor = getPrefs(context).edit();
editor.remove(key);
editor.commit();
}
private static SharedPreferences getPrefs(Context context) {
return PreferenceManager.getDefaultSharedPreferences(context);
}

Loading…
Cancel
Save