Some sync adapter code and bugfixes around it - not yet functional

This commit is contained in:
2015-10-08 14:11:45 +02:00
parent 3c7fd02613
commit 348fa8daed
16 changed files with 556 additions and 135 deletions

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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
}
}
}

View File

@ -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();
}
}