Fleshed out syncAdapter. Still needs more work.

This commit is contained in:
Nils Norman Haukås 2015-04-19 20:43:15 +02:00
parent 0846b90952
commit 81dde7c961
10 changed files with 311 additions and 27 deletions

View file

@ -3,6 +3,12 @@
package="no.nilsnh.uibevents" >
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission
android:name="android.permission.READ_SYNC_SETTINGS"/>
<uses-permission
android:name="android.permission.WRITE_SYNC_SETTINGS"/>
<uses-permission
android:name="android.permission.AUTHENTICATE_ACCOUNTS"/>
<application
android:allowBackup="true"
@ -23,6 +29,29 @@
android:name=".data.EventProvider"
android:exported="false"
android:syncable="true" />
<!-- SyncAdapter's dummy authentication service -->
<service android:name=".sync.UibEventsAuthenticatorService">
<intent-filter>
<action android:name="android.accounts.AccountAuthenticator" />
</intent-filter>
<meta-data
android:name="android.accounts.AccountAuthenticator"
android:resource="@xml/authenticator" />
</service>
<!-- The SyncAdapter service -->
<service
android:name=".sync.UibEventsSyncService"
android:exported="true"
>
<intent-filter>
<action android:name="android.content.SyncAdapter" />
</intent-filter>
<meta-data
android:name="android.content.SyncAdapter"
android:resource="@xml/syncadapter" />
</service>
</application>
</manifest>

View file

@ -1,15 +1,13 @@
package no.nilsnh.uibevents;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.StrictMode;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import no.nilsnh.uibevents.data.EventDbHelper;
import no.nilsnh.uibevents.sync.UibEventsSyncAdapter;
public class MainActivity extends ActionBarActivity implements EventFragment.Callback {
@ -45,6 +43,8 @@ public class MainActivity extends ActionBarActivity implements EventFragment.Cal
// EventFragment eventFragment = ((EventFragment)getSupportFragmentManager()
// .findFragmentById(R.id.fragment_forecast));
// eventFragment.setUseTodayLayout(!mTwoPane);
UibEventsSyncAdapter.initializeSyncAdapter(this);
}

View file

@ -1,24 +0,0 @@
package no.nilsnh.uibevents.sync;
import android.accounts.Account;
import android.content.AbstractThreadedSyncAdapter;
import android.content.ContentProviderClient;
import android.content.Context;
import android.content.SyncResult;
import android.os.Bundle;
import android.util.Log;
public class EventSyncAdapter extends AbstractThreadedSyncAdapter {
public final String LOG_TAG = EventSyncAdapter.class.getSimpleName();
public static final int SYNC_INTERVAL = 60 * 180;
public EventSyncAdapter(Context context, boolean autoInitialize) {
super(context, autoInitialize);
}
@Override
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
Log.d(LOG_TAG, "Starting sync");
}
}

View file

@ -0,0 +1,83 @@
package no.nilsnh.uibevents.sync;
import android.accounts.AbstractAccountAuthenticator;
import android.accounts.Account;
import android.accounts.AccountAuthenticatorResponse;
import android.accounts.NetworkErrorException;
import android.content.Context;
import android.os.Bundle;
/**
* Manages "Authentication" to Sunshine's backend service. The SyncAdapter framework
* requires an authenticator object, so syncing to a service that doesn't need authentication
* typically means creating a stub authenticator like this one.
* This code is copied directly, in its entirety, from
* http://developer.android.com/training/sync-adapters/creating-authenticator.html
* Which is a pretty handy reference when creating your own syncadapters. Just sayin'.
*/
public class UibEventsAuthenticator extends AbstractAccountAuthenticator {
public UibEventsAuthenticator(Context context) {
super(context);
}
// No properties to edit.
@Override
public Bundle editProperties(
AccountAuthenticatorResponse r, String s) {
throw new UnsupportedOperationException();
}
// Because we're not actually adding an account to the device, just return null.
@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,28 @@
package no.nilsnh.uibevents.sync;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
/**
* The service which allows the sync adapter framework to access the authenticator.
*/
public class UibEventsAuthenticatorService extends Service {
// Instance field that stores the authenticator object
private UibEventsAuthenticator mAuthenticator;
@Override
public void onCreate() {
// Create a new authenticator object
mAuthenticator = new UibEventsAuthenticator(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 mAuthenticator.getIBinder();
}
}

View file

@ -0,0 +1,126 @@
package no.nilsnh.uibevents.sync;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.content.AbstractThreadedSyncAdapter;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.Context;
import android.content.SyncRequest;
import android.content.SyncResult;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import no.nilsnh.uibevents.R;
public class UibEventsSyncAdapter extends AbstractThreadedSyncAdapter {
public final String LOG_TAG = UibEventsSyncAdapter.class.getSimpleName();
public static final int SYNC_INTERVAL = 60 * 180;
public static final int SYNC_FLEXTIME = SYNC_INTERVAL/3;
public UibEventsSyncAdapter(Context context, boolean autoInitialize) {
super(context, autoInitialize);
}
//Downloads and enters it into db
@Override
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
Log.d(LOG_TAG, "Starting sync");
}
public static void initializeSyncAdapter(Context context) {
getSyncAccount(context);
}
/**
* Helper method to schedule the sync adapter periodic execution
*/
public static void configurePeriodicSync(Context context, int syncInterval, int flexTime) {
Account account = getSyncAccount(context);
String authority = context.getString(R.string.content_authority);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
// we can enable inexact timers in our periodic sync
SyncRequest request = new SyncRequest.Builder().
syncPeriodic(syncInterval, flexTime).
setSyncAdapter(account, authority).
setExtras(new Bundle()).build();
ContentResolver.requestSync(request);
} else {
ContentResolver.addPeriodicSync(account,
authority, new Bundle(), syncInterval);
}
}
/**
* Helper method to have the sync adapter sync immediately
* @param context The context used to access the account service
*/
public static void syncImmediately(Context context) {
Bundle bundle = new Bundle();
bundle.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
ContentResolver.requestSync(getSyncAccount(context),
context.getString(R.string.content_authority), bundle);
}
/**
* Helper method to get the fake account to be used with SyncAdapter, or make a new one
* if the fake account doesn't exist yet. If we make a new account, we call the
* onAccountCreated method so we can initialize things.
*
* @param context The context used to access the account service
* @return a fake account.
*/
public static Account getSyncAccount(Context context) {
// Get an instance of the Android account manager
AccountManager accountManager =
(AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE);
// Create the account type and default account
Account newAccount = new Account(
context.getString(R.string.app_name), context.getString(R.string.sync_account_type));
// If the password doesn't exist, the account doesn't exist
if ( null == accountManager.getPassword(newAccount) ) {
/*
* Add the account and account type, no password or user data
* If successful, return the Account object, otherwise report an error.
*/
if (!accountManager.addAccountExplicitly(newAccount, "", null)) {
return null;
}
/*
* If you don't set android:syncable="true" in
* in your <provider> element in the manifest,
* then call ContentResolver.setIsSyncable(account, AUTHORITY, 1)
* here.
*/
onAccountCreated(newAccount, context);
}
return newAccount;
}
private static void onAccountCreated(Account newAccount, Context context) {
/*
* Since we've created an account
*/
UibEventsSyncAdapter.configurePeriodicSync(context, SYNC_INTERVAL, SYNC_FLEXTIME);
/*
* Without calling setSyncAutomatically, our periodic sync will not be enabled.
*/
ContentResolver.setSyncAutomatically(newAccount, context.getString(R.string.content_authority), true);
/*
* Finally, let's do a sync to get things started
*/
syncImmediately(context);
}
}

View file

@ -0,0 +1,26 @@
package no.nilsnh.uibevents.sync;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
public class UibEventsSyncService extends Service {
private static final Object sSyncAdapterLock = new Object();
private static UibEventsSyncAdapter uibEventsSyncAdapter = null;
@Override
public void onCreate() {
Log.d("SunshineSyncService", "onCreate - SunshineSyncService");
synchronized (sSyncAdapterLock) {
if (uibEventsSyncAdapter == null) {
uibEventsSyncAdapter = new UibEventsSyncAdapter(getApplicationContext(), true);
}
}
}
@Override
public IBinder onBind(Intent intent) {
return uibEventsSyncAdapter.getSyncAdapterBinder();
}
}

View file

@ -8,4 +8,5 @@
<string name="list_item_date_from_textview">18.11.15</string>
<string name="list_item_date_to_textview">20.11.15</string>
<string name="list_item_title_textview">The Norwegian Constitution \"VI: 1814 - 2014\"</string>
<string name="sync_account_type">uibevents.nilsnh.no</string>
</resources>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
android:accountType="@string/sync_account_type"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:smallIcon="@mipmap/ic_launcher" />

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
android:contentAuthority="@string/content_authority"
android:accountType="@string/sync_account_type"
android:userVisible="false"
android:supportsUploading="false"
android:allowParallelSyncs="false"
android:isAlwaysSyncable="true" />