-
-
Save frestoinc/69ba2242dd147b3de076d2b392c35025 to your computer and use it in GitHub Desktop.
Sync Adapter example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<manifest xmlns:android="http://schemas.android.com/apk/res/android" | |
package="com.packagename"> | |
<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="false" | |
android:label="@string/app_name" | |
android:supportsRtl="true"> | |
<service android:name=".AuthenticatorService"> | |
<intent-filter> | |
<action android:name="android.accounts.AccountAuthenticator" /> | |
</intent-filter> | |
<meta-data | |
android:name="android.accounts.AccountAuthenticator" | |
android:resource="@xml/authenticator" /> | |
</service> | |
<provider | |
android:name=".StubContentProvider" | |
android:authorities="@string/authority" | |
android:exported="false" | |
android:syncable="true" /> | |
<service | |
android:name=".ConfigurationSyncAdapterService" | |
android:exported="true" | |
android:process=":sync"> | |
<intent-filter> | |
<action android:name="android.content.SyncAdapter" /> | |
</intent-filter> | |
<meta-data | |
android:name="android.content.SyncAdapter" | |
android:resource="@xml/syncadapter" /> | |
</service> | |
</application> | |
</manifest> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class Authenticator extends AbstractAccountAuthenticator { | |
public Authenticator(final Context context) { | |
super(context); | |
} | |
/** | |
* Returns a Bundle that contains the Intent of the activity that can be used to edit the | |
* properties. In order to indicate success the activity should call response.setResult() with a | |
* non-null Bundle. | |
* | |
* @param response used to set the result for the request. If the Constants.INTENT_KEY is set | |
* in the bundle then this response field is to be used for sending future | |
* results if and when the Intent is started. | |
* @param accountType the AccountType whose properties are to be edited. | |
* @return a Bundle containing the result or the Intent to start to continue the request. If | |
* this is null then the request is considered to still be active and the result should sent | |
* later using response. | |
*/ | |
@Override | |
public Bundle editProperties(final AccountAuthenticatorResponse response, | |
final String accountType) { | |
throw new UnsupportedOperationException(); | |
} | |
/** | |
* Adds an account of the specified accountType. | |
* | |
* @param response to send the result back to the AccountManager, will never be null | |
* @param accountType the type of account to add, will never be null | |
* @param authTokenType the type of auth token to retrieve after adding the account, may be | |
* null | |
* @param requiredFeatures a String array of authenticator-specific features that the added | |
* account must support, may be null | |
* @param options a Bundle of authenticator-specific options, may be null | |
* @return a Bundle result or null if the result is to be returned via the response. The result | |
* will contain either: <ul> <li> {@link AccountManager#KEY_INTENT}, or <li> {@link | |
* AccountManager#KEY_ACCOUNT_NAME} and {@link AccountManager#KEY_ACCOUNT_TYPE} of the account | |
* that was added, or <li> {@link AccountManager#KEY_ERROR_CODE} and {@link | |
* AccountManager#KEY_ERROR_MESSAGE} to indicate an error </ul> | |
* @throws NetworkErrorException if the authenticator could not honor the request due to a | |
* network error | |
*/ | |
@Override | |
public Bundle addAccount(final AccountAuthenticatorResponse response, final String accountType, | |
final String authTokenType, final String[] requiredFeatures, | |
final Bundle options) | |
throws NetworkErrorException { | |
return null; | |
} | |
/** | |
* Checks that the user knows the credentials of an account. | |
* | |
* @param response to send the result back to the AccountManager, will never be null | |
* @param account the account whose credentials are to be checked, will never be null | |
* @param options a Bundle of authenticator-specific options, may be null | |
* @return a Bundle result or null if the result is to be returned via the response. The result | |
* will contain either: <ul> <li> {@link AccountManager#KEY_INTENT}, or <li> {@link | |
* AccountManager#KEY_BOOLEAN_RESULT}, true if the check succeeded, false otherwise <li> {@link | |
* AccountManager#KEY_ERROR_CODE} and {@link AccountManager#KEY_ERROR_MESSAGE} to indicate an | |
* error </ul> | |
* @throws NetworkErrorException if the authenticator could not honor the request due to a | |
* network error | |
*/ | |
@Override | |
public Bundle confirmCredentials(final AccountAuthenticatorResponse response, | |
final Account account, | |
final Bundle options) throws NetworkErrorException { | |
return null; | |
} | |
/** | |
* Gets an authtoken for an account. | |
* <p> | |
* If not {@code null}, the resultant {@link Bundle} will contain different sets of keys | |
* depending on whether a token was successfully issued and, if not, whether one could be issued | |
* via some {@link Activity}. | |
* <p> | |
* If a token cannot be provided without some additional activity, the Bundle should contain | |
* {@link AccountManager#KEY_INTENT} with an associated {@link Intent}. On the other hand, if | |
* there is no such activity, then a Bundle containing {@link AccountManager#KEY_ERROR_CODE} and | |
* {@link AccountManager#KEY_ERROR_MESSAGE} should be returned. | |
* <p> | |
* If a token can be successfully issued, the implementation should return the {@link | |
* AccountManager#KEY_ACCOUNT_NAME} and {@link AccountManager#KEY_ACCOUNT_TYPE} of the account | |
* associated with the token as well as the {@link AccountManager#KEY_AUTHTOKEN}. In addition | |
* {@link AbstractAccountAuthenticator} implementations that declare themselves {@code | |
* android:customTokens=true} may also provide a non-negative {@link #KEY_CUSTOM_TOKEN_EXPIRY} | |
* long value containing the expiration timestamp of the expiration time (in millis since the | |
* unix epoch). | |
* <p> | |
* Implementers should assume that tokens will be cached on the basis of account and | |
* authTokenType. The system may ignore the contents of the supplied options Bundle when | |
* determining to re-use a cached token. Furthermore, implementers should assume a supplied | |
* expiration time will be treated as non-binding advice. | |
* <p> | |
* Finally, note that for android:customTokens=false authenticators, tokens are cached | |
* indefinitely until some client calls {@link AccountManager#invalidateAuthToken(String, | |
* String)}. | |
* | |
* @param response to send the result back to the AccountManager, will never be null | |
* @param account the account whose credentials are to be retrieved, will never be null | |
* @param authTokenType the type of auth token to retrieve, will never be null | |
* @param options a Bundle of authenticator-specific options, may be null | |
* @return a Bundle result or null if the result is to be returned via the response. | |
* @throws NetworkErrorException if the authenticator could not honor the request due to a | |
* network error | |
*/ | |
@Override | |
public Bundle getAuthToken(final AccountAuthenticatorResponse response, final Account account, | |
final String authTokenType, final Bundle options) | |
throws NetworkErrorException { | |
throw new UnsupportedOperationException(); | |
} | |
/** | |
* Ask the authenticator for a localized label for the given authTokenType. | |
* | |
* @param authTokenType the authTokenType whose label is to be returned, will never be null | |
* @return the localized label of the auth token type, may be null if the type isn't known | |
*/ | |
@Override | |
public String getAuthTokenLabel(final String authTokenType) { | |
throw new UnsupportedOperationException(); | |
} | |
/** | |
* Update the locally stored credentials for an account. | |
* | |
* @param response to send the result back to the AccountManager, will never be null | |
* @param account the account whose credentials are to be updated, will never be null | |
* @param authTokenType the type of auth token to retrieve after updating the credentials, may | |
* be null | |
* @param options a Bundle of authenticator-specific options, may be null | |
* @return a Bundle result or null if the result is to be returned via the response. The result | |
* will contain either: <ul> <li> {@link AccountManager#KEY_INTENT}, or <li> {@link | |
* AccountManager#KEY_ACCOUNT_NAME} and {@link AccountManager#KEY_ACCOUNT_TYPE} of the account | |
* whose credentials were updated, or <li> {@link AccountManager#KEY_ERROR_CODE} and {@link | |
* AccountManager#KEY_ERROR_MESSAGE} to indicate an error </ul> | |
* @throws NetworkErrorException if the authenticator could not honor the request due to a | |
* network error | |
*/ | |
@Override | |
public Bundle updateCredentials(final AccountAuthenticatorResponse response, | |
final Account account, | |
final String authTokenType, final Bundle options) | |
throws NetworkErrorException { | |
throw new UnsupportedOperationException(); | |
} | |
/** | |
* Checks if the account supports all the specified authenticator specific features. | |
* | |
* @param response to send the result back to the AccountManager, will never be null | |
* @param account the account to check, will never be null | |
* @param features an array of features to check, will never be null | |
* @return a Bundle result or null if the result is to be returned via the response. The result | |
* will contain either: <ul> <li> {@link AccountManager#KEY_INTENT}, or <li> {@link | |
* AccountManager#KEY_BOOLEAN_RESULT}, true if the account has all the features, false otherwise | |
* <li> {@link AccountManager#KEY_ERROR_CODE} and {@link AccountManager#KEY_ERROR_MESSAGE} to | |
* indicate an error </ul> | |
* @throws NetworkErrorException if the authenticator could not honor the request due to a | |
* network error | |
*/ | |
@Override | |
public Bundle hasFeatures(final AccountAuthenticatorResponse response, final Account account, | |
final String[] features) throws NetworkErrorException { | |
throw new UnsupportedOperationException(); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android" | |
android:accountType="@string/account_type" | |
android:icon="@mipmap/ic_launcher" | |
android:label="@string/app_name" | |
android:smallIcon="@mipmap/ic_launcher" /> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class AuthenticatorService extends Service { | |
private Authenticator authenticator; | |
@Override | |
public void onCreate() { | |
authenticator = new Authenticator(this); | |
} | |
@Override | |
public IBinder onBind(Intent intent) { | |
return authenticator.getIBinder(); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class ConfigurationSyncAdapter extends AbstractThreadedSyncAdapter { | |
private static final String TAG = ConfigurationSyncAdapter.class.getSimpleName(); | |
ConfigurationSyncAdapter(final Context context, final boolean autoInitialize) { | |
super(context, autoInitialize); | |
} | |
ConfigurationSyncAdapter(final Context context, final boolean autoInitialize, | |
final boolean allowParallelSyncs) { | |
super(context, autoInitialize, allowParallelSyncs); | |
manager = new ApolloBackendConfigurationManager(context); | |
} | |
/** | |
* Perform a sync for this account. SyncAdapter-specific parameters may be specified in extras, | |
* which is guaranteed to not be null. Invocations of this method are guaranteed to be | |
* serialized. | |
* | |
* @param account the account that should be synced | |
* @param extras SyncAdapter-specific parameters | |
* @param authority the authority of this sync request | |
* @param provider a ContentProviderClient that points to the ContentProvider for this | |
* authority | |
* @param syncResult SyncAdapter-specific parameters | |
*/ | |
@Override | |
public void onPerformSync(final Account account, final Bundle extras, final String authority, | |
final ContentProviderClient provider, final SyncResult syncResult) { | |
Log.i(TAG, "onPerformSync() was called"); | |
// do networking stuff here | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class ConfigurationSyncAdapterService extends AmlService { | |
private static ConfigurationSyncAdapter syncAdapter = null; | |
private static final Object syncAdapterLock = new Object(); | |
@Override | |
public void onCreate() { | |
super.onCreate(); | |
/* | |
* Create the sync adapter as a singleton. | |
* Set the sync adapter as syncable | |
* Disallow parallel syncs | |
*/ | |
synchronized (syncAdapterLock) { | |
if (syncAdapter == null) { | |
syncAdapter = new ConfigurationSyncAdapter(getApplicationContext(), true); | |
} | |
} | |
} | |
/** | |
* Return an object that allows the system to invoke | |
* the sync adapter. | |
* | |
*/ | |
@Override | |
public IBinder onBind(final 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(); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<resources> | |
<string name="app_name">AppName</string> | |
<string name="authority">com.packagename.authority</string> | |
<string name="account_type">some.account.type.com</string> | |
</resources> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class StubContentProvider extends ContentProvider { | |
@Override | |
public boolean onCreate() { | |
return true; | |
} | |
@Nullable | |
@Override | |
public Cursor query(@NonNull final Uri uri, final String[] projection, final String selection, | |
final String[] selectionArgs, | |
final String sortOrder) { | |
return null; | |
} | |
@Nullable | |
@Override | |
public String getType(@NonNull final Uri uri) { | |
return null; | |
} | |
@Nullable | |
@Override | |
public Uri insert(@NonNull final Uri uri, final ContentValues values) { | |
return null; | |
} | |
@Override | |
public int delete(@NonNull final Uri uri, final String selection, | |
final String[] selectionArgs) { | |
return 0; | |
} | |
@Override | |
public int update(@NonNull final Uri uri, final ContentValues values, final String selection, | |
final String[] selectionArgs) { | |
return 0; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android" | |
android:accountType="@string/account_type" | |
android:allowParallelSyncs="false" | |
android:contentAuthority="@string/authority" | |
android:isAlwaysSyncable="true" | |
android:supportsUploading="false" | |
android:userVisible="false" /> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class SyncAdapterManager { | |
private static final String TAG = SyncAdapterManager.class.getSimpleName(); | |
private final String authority; | |
private final String type; | |
private Account account; | |
private Context context; | |
SyncAdapterManager(final Context context) { | |
this.context = context; | |
type = context.getString(R.string.account_type); | |
authority = context.getString(R.string.authority); | |
account = new Account(context.getString(R.string.app_name), type); | |
} | |
@SuppressWarnings ("MissingPermission") | |
void beginPeriodicSync(final long updateConfigInterval) { | |
Log.d(TAG, "beginPeriodicSync() called with: updateConfigInterval = [" + | |
updateConfigInterval + "]"); | |
final AccountManager accountManager = (AccountManager) context | |
.getSystemService(ACCOUNT_SERVICE); | |
if (!accountManager.addAccountExplicitly(account, null, null)) { | |
account = accountManager.getAccountsByType(type)[0]; | |
} | |
setAccountSyncable(); | |
ContentResolver.addPeriodicSync(account, context.getString(R.string.authority), | |
Bundle.EMPTY, updateConfigInterval); | |
ContentResolver.setSyncAutomatically(account, authority, true); | |
} | |
void syncImmediately() { | |
Bundle settingsBundle = new Bundle(); | |
settingsBundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true); | |
settingsBundle.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true); | |
ContentResolver.requestSync(account, authority, settingsBundle); | |
} | |
private void setAccountSyncable() { | |
if (ContentResolver.getIsSyncable(account, authority) == 0) { | |
ContentResolver.setIsSyncable(account, authority, 1); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment