Last active
August 29, 2015 14:11
-
-
Save rburgosnavas/f3cd7c7c2e3ff640bda4 to your computer and use it in GitHub Desktop.
Sync Adapter
This file contains 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.rburgosnavas.droidfs" > | |
<uses-permission android:name="android.permission.INTERNET" /> | |
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> | |
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS"/> | |
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS"/> | |
<uses-permission android:name="android.permission.READ_SYNC_STATS"/> | |
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS"/> | |
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS"/> | |
<application | |
android:allowBackup="true" | |
android:icon="@drawable/ic_launcher" | |
android:label="@string/app_name" | |
android:theme="@style/AppTheme" | |
android:enabled="true" > | |
<provider | |
android:name=".syncadapter.provider.StubProvider" | |
android:authorities="com.rburgosnavas.droidfs.provider" | |
android:label="droidfs provider" | |
android:enabled="true" | |
android:exported="false" | |
android:syncable="true" > | |
</provider> | |
<service | |
android:name=".syncadapter.SyncService" | |
android:enabled="true" | |
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> | |
<service | |
android:name=".syncadapter.AuthenticatorService"> | |
<intent-filter> | |
<action android:name="android.accounts.AccountAuthenticator" /> | |
</intent-filter> | |
<meta-data | |
android:name="android.accounts.AccountAuthenticator" | |
android:resource="@xml/authenticator" /> | |
</service> | |
<activity | |
android:name=".MainActivity" | |
android:label="@string/app_name" > | |
<intent-filter> | |
<action android:name="android.intent.action.MAIN" /> | |
<category android:name="android.intent.category.LAUNCHER" /> | |
</intent-filter> | |
</activity> | |
<activity | |
android:name=".RecentSoundsActivity" | |
android:label="@string/title_activity_recent_sounds" > | |
</activity> | |
</application> | |
</manifest> |
This file contains 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
package com.rburgosnavas.droidfs.syncadapter; | |
import android.accounts.AbstractAccountAuthenticator; | |
import android.accounts.Account; | |
import android.accounts.AccountAuthenticatorResponse; | |
import android.accounts.NetworkErrorException; | |
import android.content.Context; | |
import android.os.Bundle; | |
import android.util.Log; | |
/** | |
* Created by rburgosnavas on 12/11/14. | |
*/ | |
public class Authenticator extends AbstractAccountAuthenticator{ | |
public Authenticator(Context context) { | |
super(context); | |
Log.i("Authenticator", "created"); | |
} | |
@Override | |
public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) { | |
throw new UnsupportedOperationException(); | |
} | |
@Override | |
public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType, String[] requiredFeatures, Bundle options) throws NetworkErrorException { | |
return null; | |
} | |
@Override | |
public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account, Bundle options) throws NetworkErrorException { | |
return null; | |
} | |
@Override | |
public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException { | |
throw new UnsupportedOperationException(); | |
} | |
@Override | |
public String getAuthTokenLabel(String authTokenType) { | |
throw new UnsupportedOperationException(); | |
} | |
@Override | |
public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException { | |
throw new UnsupportedOperationException(); | |
} | |
@Override | |
public Bundle hasFeatures(AccountAuthenticatorResponse response, Account account, String[] features) throws NetworkErrorException { | |
throw new UnsupportedOperationException(); | |
} | |
} |
This file contains 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="com.rburgosnavas.droifs" | |
android:icon="@drawable/ic_launcher" | |
android:smallIcon="@drawable/ic_launcher" | |
android:label="@string/app_name" | |
/> |
This file contains 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
package com.rburgosnavas.droidfs.syncadapter; | |
import android.app.Service; | |
import android.content.Intent; | |
import android.os.IBinder; | |
import android.util.Log; | |
public class AuthenticatorService extends Service { | |
private Authenticator authenticator; | |
@Override | |
public void onCreate() { | |
super.onCreate(); | |
authenticator = new Authenticator(this); | |
Log.i("AuthenticatorService", "created"); | |
} | |
@Override | |
public int onStartCommand(Intent intent, int flags, int startId) { | |
Log.i("AuthenticatorService", "on start command"); | |
return super.onStartCommand(intent, flags, startId); | |
} | |
@Override | |
public void onDestroy() { | |
super.onDestroy(); | |
Log.i("AuthenticatorService", "destroyed"); | |
} | |
@Override | |
public boolean onUnbind(Intent intent) { | |
Log.i("AuthenticatorService", "unbound"); | |
return super.onUnbind(intent); | |
} | |
@Override | |
public void onRebind(Intent intent) { | |
super.onRebind(intent); | |
Log.i("AuthenticatorService", "rebound"); | |
} | |
@Override | |
public IBinder onBind(Intent intent) { | |
// TODO: Return the communication channel to the service. | |
Log.i("AuthenticatorService", "binding..."); | |
return authenticator.getIBinder(); | |
} | |
} |
This file contains 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
package com.rburgosnavas.droidfs.syncadapter; | |
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.AsyncTask; | |
import android.os.Bundle; | |
import android.util.Log; | |
import com.google.gson.JsonObject; | |
import com.google.gson.JsonParser; | |
import com.rburgosnavas.droidfs.clients.HttpAuthClient; | |
import com.rburgosnavas.droidfs.utils.AuthUtils; | |
import java.io.IOException; | |
import java.util.Calendar; | |
/** | |
* Created by rburgosnavas on 12/11/14. | |
*/ | |
public class AuthenticatorSyncAdapter extends AbstractThreadedSyncAdapter{ | |
private static final String TAG = AuthenticatorSyncAdapter.class.getSimpleName(); | |
private SharedPreferences prefs; | |
public AuthenticatorSyncAdapter(Context context, boolean autoInitialize) { | |
super(context, autoInitialize); | |
Log.i(TAG, "sync adapter created"); | |
prefs = context.getSharedPreferences("OAUTH_PREFS", Context.MODE_PRIVATE); | |
} | |
public AuthenticatorSyncAdapter(Context context, boolean autoInitialize, | |
boolean allowParallelSyncs) { | |
super(context, autoInitialize, allowParallelSyncs); | |
Log.i(TAG, "sync adapter created"); | |
prefs = context.getSharedPreferences("OAUTH_PREFS", Context.MODE_PRIVATE); | |
} | |
@Override | |
public void onPerformSync(Account account, Bundle extras, String authority, | |
ContentProviderClient provider, SyncResult syncResult) { | |
Log.w(TAG, "performing sync"); | |
if (prefs.contains("ACCESS_TOKEN")) { | |
long expiration = prefs.getLong("EXPIRATION_TIMESTAMP", -1); | |
if (AuthUtils.isExpired(expiration)) { | |
Log.w(TAG, "access_token=" + prefs.getString("ACCESS_TOKEN", "") + " expired."); | |
final String refreshToken = prefs.getString("REFRESH_TOKEN", ""); | |
if (!"".equals(refreshToken)) { | |
// TODO network IO | |
new AsyncTask<String, String, JsonObject>() { | |
@Override | |
protected void onPreExecute() { | |
super.onPreExecute(); | |
} | |
@Override | |
protected void onPostExecute(JsonObject token) { | |
super.onPostExecute(token); | |
SharedPreferences prefs = getContext().getSharedPreferences("OAUTH_PREFS", Context.MODE_PRIVATE); | |
SharedPreferences.Editor editor = prefs.edit(); | |
editor.putString("ACCESS_TOKEN", token.get("access_token").getAsString()); | |
Calendar c = Calendar.getInstance(); | |
editor.putLong("ACCESS_TIMESTAMP", c.getTimeInMillis()); | |
int time = token.get("expires_in").getAsInt(); | |
c.set(Calendar.SECOND, time); | |
editor.putInt("EXPIRES_IN", time); | |
editor.putLong("EXPIRATION_TIMESTAMP", c.getTimeInMillis()); | |
editor.putString("REFRESH_TOKEN", token.get("refresh_token").getAsString()); | |
editor.apply(); | |
} | |
@Override | |
protected void onProgressUpdate(String... values) { | |
super.onProgressUpdate(values); | |
} | |
@Override | |
protected void onCancelled(JsonObject jsonObject) { | |
super.onCancelled(jsonObject); | |
} | |
@Override | |
protected JsonObject doInBackground(String... params) { | |
String bodyString = null; | |
try { | |
Log.i(TAG, "getting refresh token"); | |
bodyString = HttpAuthClient.getRefreshToken(params[0]).body().string(); | |
Log.i(TAG, "RESPONSE = " + bodyString); | |
} catch (IOException e) { | |
e.printStackTrace(); | |
} | |
JsonObject j = new JsonParser().parse(bodyString).getAsJsonObject(); | |
return j; | |
} | |
}; | |
} | |
} else { | |
Log.i(TAG, "access_token=" + prefs.getString("ACCESS_TOKEN", "") + " valid."); | |
} | |
} | |
} | |
} |
This file contains 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
package com.rburgosnavas.droidfs; | |
import // ... | |
public class MainActivity extends Activity implements LoginWebViewClient.OnAuthorizationCodeListener, AuthTask.AuthListener { | |
// Constants ---------------------------------------------------------------------------------- | |
private static final String TAG = MainActivity.class.getSimpleName(); | |
// ... | |
private SharedPreferences prefs; | |
private Account account; | |
@Override | |
protected void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.activity_main); | |
createSyncAccount(this); | |
prefs = getApplicationContext().getSharedPreferences("OAUTH_PREFS", Context.MODE_PRIVATE); | |
// ... | |
} | |
// ... | |
/** | |
* Create a new dummy account for the sync adapter | |
* | |
* @param context The application context | |
*/ | |
public static void createSyncAccount(Context context) { | |
// Create the account type and default account | |
Account newAccount = new Account("Test Account", "com.rburgosnavas.droifs"); | |
Log.i(TAG, "account created"); | |
// Get an instance of the Android account manager | |
AccountManager accountManager = (AccountManager) context.getSystemService(ACCOUNT_SERVICE); | |
/* | |
* Add the account and account type, no password or user data | |
* If successful, return the Account object, otherwise report an error. | |
*/ | |
boolean isAdded = accountManager.addAccountExplicitly(newAccount, null, null); | |
if (isAdded) { | |
ContentResolver.setIsSyncable(newAccount, "com.rburgosnavas.droidfs.provider", 1); | |
ContentResolver.setSyncAutomatically(newAccount, "com.rburgosnavas.droidfs.provider", true); | |
ContentResolver.addPeriodicSync(newAccount, "com.rburgosnavas.droidfs.provider", Bundle.EMPTY, 60); | |
Log.i(TAG, "added periodically"); | |
} else { | |
Log.i(TAG, "request sync"); | |
ContentResolver.requestSync(newAccount, "com.rburgosnavas.droidfs.provider", Bundle.EMPTY); | |
} | |
} | |
} |
This file contains 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:contentAuthority="com.rburgosnavas.droifs.provider" | |
android:accountType="com.rburgosnavas.droifs" | |
android:userVisible="true" | |
android:supportsUploading="false" | |
android:allowParallelSyncs="false" | |
android:isAlwaysSyncable="false"/> |
This file contains 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
package com.rburgosnavas.droidfs.syncadapter; | |
import android.app.Service; | |
import android.content.Intent; | |
import android.os.IBinder; | |
import android.util.Log; | |
public class SyncService extends Service { | |
private static AuthenticatorSyncAdapter syncAdapter = null; | |
private static final Object syncAdapterLock = new Object(); | |
@Override | |
public void onCreate() { | |
super.onCreate(); | |
Log.i("SyncService", "service created"); | |
synchronized (syncAdapterLock) { | |
if (syncAdapter == null) { | |
syncAdapter = new AuthenticatorSyncAdapter(getApplicationContext(), true); | |
Log.i("SyncService", "SyncAdapter created"); | |
} | |
} | |
} | |
@Override | |
public void onDestroy() { | |
super.onDestroy(); | |
Log.i("SyncService", "service destroyed"); | |
} | |
@Override | |
public boolean onUnbind(Intent intent) { | |
Log.i("SyncService", "service unbound | intent=" + intent.getDataString()); | |
return super.onUnbind(intent); | |
} | |
@Override | |
public void onRebind(Intent intent) { | |
super.onRebind(intent); | |
Log.i("SyncService", "service rebound"); | |
} | |
@Override | |
public int onStartCommand(Intent intent, int flags, int startId) { | |
Log.i("SyncService", "on start command"); | |
return super.onStartCommand(intent, flags, startId); | |
} | |
@Override | |
public IBinder onBind(Intent intent) { | |
Log.i("SyncService", "binding..."); | |
return syncAdapter.getSyncAdapterBinder(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment