Some sync adapter code and bugfixes around it - not yet functional
This commit is contained in:
@ -0,0 +1,82 @@
|
||||
package ch.dissem.apps.abit.synchronization;
|
||||
|
||||
import android.accounts.AbstractAccountAuthenticator;
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AccountAuthenticatorResponse;
|
||||
import android.accounts.NetworkErrorException;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
|
||||
/*
|
||||
* Implement AbstractAccountAuthenticator and stub out all
|
||||
* of its methods
|
||||
*/
|
||||
public class Authenticator extends AbstractAccountAuthenticator {
|
||||
public static final String ACCOUNT_NAME = "Bitmessage";
|
||||
public static final String ACCOUNT_TYPE = "bitmessage.dissem.ch";
|
||||
|
||||
// Simple constructor
|
||||
public Authenticator(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
// Editing properties is not supported
|
||||
@Override
|
||||
public Bundle editProperties(
|
||||
AccountAuthenticatorResponse r, String s) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
// Don't add additional accounts
|
||||
@Override
|
||||
public Bundle addAccount(
|
||||
AccountAuthenticatorResponse r,
|
||||
String s,
|
||||
String s2,
|
||||
String[] strings,
|
||||
Bundle bundle) throws NetworkErrorException {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Ignore attempts to confirm credentials
|
||||
@Override
|
||||
public Bundle confirmCredentials(
|
||||
AccountAuthenticatorResponse r,
|
||||
Account account,
|
||||
Bundle bundle) throws NetworkErrorException {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Getting an authentication token is not supported
|
||||
@Override
|
||||
public Bundle getAuthToken(
|
||||
AccountAuthenticatorResponse r,
|
||||
Account account,
|
||||
String s,
|
||||
Bundle bundle) throws NetworkErrorException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
// Getting a label for the auth token is not supported
|
||||
@Override
|
||||
public String getAuthTokenLabel(String s) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
// Updating user credentials is not supported
|
||||
@Override
|
||||
public Bundle updateCredentials(
|
||||
AccountAuthenticatorResponse r,
|
||||
Account account,
|
||||
String s, Bundle bundle) throws NetworkErrorException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
// Checking features for the account is not supported
|
||||
@Override
|
||||
public Bundle hasFeatures(
|
||||
AccountAuthenticatorResponse r,
|
||||
Account account, String[] strings) throws NetworkErrorException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package ch.dissem.apps.abit.synchronization;
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.Intent;
|
||||
import android.os.IBinder;
|
||||
|
||||
/**
|
||||
* A bound Service that instantiates the authenticator
|
||||
* when started.
|
||||
*/
|
||||
public class AuthenticatorService extends Service {
|
||||
/**
|
||||
* Instance field that stores the authenticator object
|
||||
*/
|
||||
private Authenticator authenticator;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
// Create a new authenticator object
|
||||
authenticator = new Authenticator(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* When the system binds to this Service to make the RPC call
|
||||
* return the authenticator's IBinder.
|
||||
*/
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return authenticator.getIBinder();
|
||||
}
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
package ch.dissem.apps.abit.synchronization;
|
||||
|
||||
import android.content.ContentProvider;
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
|
||||
/*
|
||||
* Define an implementation of ContentProvider that stubs out
|
||||
* all methods
|
||||
*/
|
||||
public class StubProvider extends ContentProvider {
|
||||
/*
|
||||
* Always return true, indicating that the
|
||||
* provider loaded correctly.
|
||||
*/
|
||||
@Override
|
||||
public boolean onCreate() {
|
||||
return true;
|
||||
}
|
||||
/*
|
||||
* Return no type for MIME type
|
||||
*/
|
||||
@Override
|
||||
public String getType(Uri uri) {
|
||||
return null;
|
||||
}
|
||||
/*
|
||||
* query() always returns no results
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
public Cursor query(
|
||||
Uri uri,
|
||||
String[] projection,
|
||||
String selection,
|
||||
String[] selectionArgs,
|
||||
String sortOrder) {
|
||||
return null;
|
||||
}
|
||||
/*
|
||||
* insert() always returns null (no URI)
|
||||
*/
|
||||
@Override
|
||||
public Uri insert(Uri uri, ContentValues values) {
|
||||
return null;
|
||||
}
|
||||
/*
|
||||
* delete() always returns "no rows affected" (0)
|
||||
*/
|
||||
@Override
|
||||
public int delete(Uri uri, String selection, String[] selectionArgs) {
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* update() always returns "no rows affected" (0)
|
||||
*/
|
||||
public int update(
|
||||
Uri uri,
|
||||
ContentValues values,
|
||||
String selection,
|
||||
String[] selectionArgs) {
|
||||
return 0;
|
||||
}
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
package ch.dissem.apps.abit.synchronization;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.content.AbstractThreadedSyncAdapter;
|
||||
import android.content.ContentProviderClient;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SyncResult;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import ch.dissem.apps.abit.service.Singleton;
|
||||
import ch.dissem.bitmessage.BitmessageContext;
|
||||
|
||||
/**
|
||||
* Sync Adapter to synchronize with the Bitmessage network - fetches
|
||||
* new objects and then disconnects.
|
||||
*/
|
||||
public class SyncAdapter extends AbstractThreadedSyncAdapter {
|
||||
private final static Logger LOG = LoggerFactory.getLogger(SyncAdapter.class);
|
||||
|
||||
public static final String AUTHORITY = "ch.dissem.bitmessage.provider";
|
||||
|
||||
private final BitmessageContext bmc;
|
||||
|
||||
public SyncAdapter(Context context) {
|
||||
super(context, true, false);
|
||||
bmc = Singleton.getBitmessageContext(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
|
||||
// If the Bitmessage context acts as a full node, synchronization isn't necessary
|
||||
if (bmc.isRunning()) return;
|
||||
|
||||
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
|
||||
String trustedNode = preferences.getString("trusted_node", null);
|
||||
if (trustedNode == null) return;
|
||||
trustedNode = trustedNode.trim();
|
||||
if (trustedNode.isEmpty()) return;
|
||||
|
||||
int port;
|
||||
if (trustedNode.matches("^(?![0-9a-fA-F]*:[0-9a-fA-F]*:).*(:[0-9]+)$")) {
|
||||
int index = trustedNode.lastIndexOf(':');
|
||||
String portString = trustedNode.substring(index + 1);
|
||||
trustedNode = trustedNode.substring(0, index);
|
||||
try {
|
||||
port = Integer.parseInt(portString);// FIXME
|
||||
} catch (NumberFormatException e) {
|
||||
LOG.error("Invalid port " + portString);
|
||||
// TODO: show error as notification
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
port = 8444;
|
||||
}
|
||||
long timeoutInSeconds = preferences.getInt("sync_timeout", 120);
|
||||
try {
|
||||
LOG.info("Synchronization started");
|
||||
bmc.synchronize(InetAddress.getByName(trustedNode), port, timeoutInSeconds, true);
|
||||
LOG.info("Synchronization finished");
|
||||
} catch (UnknownHostException e) {
|
||||
LOG.error("Couldn't synchronize", e);
|
||||
// TODO: show error as notification
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package ch.dissem.apps.abit.synchronization;
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.Intent;
|
||||
import android.os.IBinder;
|
||||
|
||||
/**
|
||||
* Define a Service that returns an IBinder for the
|
||||
* sync adapter class, allowing the sync adapter framework to call
|
||||
* onPerformSync().
|
||||
*/
|
||||
public class SyncService extends Service {
|
||||
// Storage for an instance of the sync adapter
|
||||
private static SyncAdapter syncAdapter = null;
|
||||
// Object to use as a thread-safe lock
|
||||
private static final Object syncAdapterLock = new Object();
|
||||
|
||||
/*
|
||||
* Instantiate the sync adapter object.
|
||||
*/
|
||||
@Override
|
||||
public void onCreate() {
|
||||
/*
|
||||
* Create the sync adapter as a singleton.
|
||||
* Set the sync adapter as syncable
|
||||
* Disallow parallel syncs
|
||||
*/
|
||||
synchronized (syncAdapterLock) {
|
||||
if (syncAdapter == null) {
|
||||
syncAdapter = new SyncAdapter(getApplicationContext());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an object that allows the system to invoke
|
||||
* the sync adapter.
|
||||
*/
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
/*
|
||||
* Get the object that allows external processes
|
||||
* to call onPerformSync(). The object is created
|
||||
* in the base class code when the SyncAdapter
|
||||
* constructors call super()
|
||||
*/
|
||||
return syncAdapter.getSyncAdapterBinder();
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user