Skip to content

Commit

Permalink
Normalizing AccountManager code
Browse files Browse the repository at this point in the history
  • Loading branch information
Mostafa Gazar committed Jan 14, 2015
2 parents 0fee575 + f25c933 commit 8818c35
Show file tree
Hide file tree
Showing 17 changed files with 966 additions and 8 deletions.
26 changes: 24 additions & 2 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />


<!-- @AccountManager: Permissions required for creating and managing Accounts -->
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
<!-- -->

<application
android:name="com.meg7.soas.SoasApplication"
android:allowBackup="true"
Expand Down Expand Up @@ -40,8 +48,22 @@
<provider
android:name=".database.provider.OfflineNotesProvider"
android:authorities="@string/authorities_provider_offline_notes"
android:exported="false">
</provider>
android:exported="false"></provider>

<!-- These must be declared as any action related intent is called following service is spawn off -->
<service android:name="com.meg7.soas.accounts.AccountAuthenticatorService">
<intent-filter>
<action android:name="android.accounts.AccountAuthenticator" />
</intent-filter>

<meta-data
android:name="android.accounts.AccountAuthenticator"
android:resource="@xml/account_authenticator" />
</service>

<activity android:name=".accounts.AuthActivity" />
<activity android:name=".accounts.AccountViewActivity" />
</application>


</manifest>
89 changes: 89 additions & 0 deletions app/src/main/java/com/meg7/soas/account/AccountAuthenticator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package com.meg7.soas.account;

import android.accounts.AbstractAccountAuthenticator;
import android.accounts.Account;
import android.accounts.AccountAuthenticatorResponse;
import android.accounts.AccountManager;
import android.accounts.NetworkErrorException;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;

import com.meg7.soas.ui.AccountAuthActivity;

/**
* @author Santosh Dhakal
*/
public class AccountAuthenticator extends AbstractAccountAuthenticator {

private Context mContext;

public AccountAuthenticator(Context context) {
super(context);
mContext = context;
}

@Override
public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) {
return null;
}

/**
* Whenever AddAccount action is called from anywhere, through
* AccountAuthenticatorService ,this method is invoked, here we need
* to define the class which handles Login or Sign Up like AuthActivity
* in our case. AuthActivity is responsible for validating user by communicating
* through server. AuthActivity must be subclass of AccountAuthenticatorActivity.
* If you want more control over AccountAuthenticatorActivity, look upon
* the source code and implement your own Activity class resembling AccountAuthenticatorActivity
*/
@Override
public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType, String[] requiredFeatures, Bundle options) throws NetworkErrorException {
Bundle reply = new Bundle();


Intent intent = new Intent(mContext, AccountAuthActivity.class);
intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE, accountType);
intent.putExtra(AccountManager.KEY_AUTHTOKEN, authTokenType);
if (options.containsKey(AccountAuthActivity.CALL_FROM_ADD_ACCOUNT)) {
intent.putExtra(AccountAuthActivity.CALL_FROM_ADD_ACCOUNT, true);
}

reply.putParcelable(AccountManager.KEY_INTENT, intent);

return reply;
}

@Override
public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account, Bundle options) throws NetworkErrorException {
return null;
}

/**
* Whenever getAuthToken of AccountManager is called, this
* method is invoked where you have to implement necessary logic to
* to get Auth Token
*/
@Override
public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException {
// http://udinic.wordpress.com/2013/04/24/write-your-own-android-authenticator/
return null;
}

@Override
public String getAuthTokenLabel(String authTokenType) {
return null;
}

@Override
public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException {
return null;
}

@Override
public Bundle hasFeatures(AccountAuthenticatorResponse response, Account account, String[] features) throws NetworkErrorException {
return null;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.meg7.soas.account;

import android.accounts.AccountManager;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;

/**
* @author Santosh Dhakal
*/
public class AccountAuthenticatorService extends Service {

private static AccountAuthenticator mAccountAuthenticator;

/**
* Account creation and other related Action when called in the app
* this Service is called. Then this Service, calls relevant AccountAuthenticator
* as defined onBind
*/
@Override
public IBinder onBind(Intent intent) {
IBinder binder = null;
if (intent.getAction().equals(AccountManager.ACTION_AUTHENTICATOR_INTENT)) {
binder = getAccountAuthenticator().getIBinder();
}

return binder;
}

private AccountAuthenticator getAccountAuthenticator() {
if (mAccountAuthenticator == null) {
mAccountAuthenticator = new AccountAuthenticator(this);
}

return mAccountAuthenticator;
}

}
118 changes: 118 additions & 0 deletions app/src/main/java/com/meg7/soas/account/SoasAccountManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package com.meg7.soas.account;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.os.Bundle;

import com.meg7.soas.data.User;

import java.util.Arrays;
import java.util.List;

/**
* @author Santosh Dhakal
*/
public class SoasAccountManager {

/**
* Keep in mind ACCOUNT_TYPE value declared here
* must be same as xml/account_authenticator android:accountType
* It is not necessary that you give your Application package name as done in here,
* you can give your own AccountType
* but keep in mind it should be same value defined on xml/account_authenticator
*/
public static final String ACCOUNT_TYPE = "com.meg7.soas";

/**
* Your own Account Auth Type like OAuth,OAuth2.0 and so on
*/
public static final String ACCOUNT_AUTH_TYPE = "soas_auth";
public static final String USER_EMAIL = "email";
public static final String USER_NAME = "name";
public static final String USER_UNAME = "uname";
public static final String USER_AUTH_TOKEN = "authToken";

private final AccountManager mAccountManager;

public SoasAccountManager(AccountManager accountManager) {
if (accountManager == null) {
throw new NullPointerException("AccountManager cannot be null");
}

mAccountManager = accountManager;
}

/**
* Listing all the accounts by our Account type
* ie. ACCOUNT_TYPE="com.meg7.soas
* right now we are only taking a single account,but
* multiple accounts can be created or added
* as per the need of the app
*/
public List<Account> getAccounts() {
final Account[] accounts = mAccountManager.getAccountsByType(ACCOUNT_TYPE);

return Arrays.asList(accounts);
}

/**
* Method to create a new Account
*/
public void addAccount(User user) {

Account account = new Account(user.email, ACCOUNT_TYPE);
Bundle userData = new Bundle();
userData.putString(USER_UNAME, user.uname);
userData.putString(USER_EMAIL, user.email);
userData.putString(USER_NAME, user.name);
userData.putString(USER_AUTH_TOKEN, user.authToken);
mAccountManager.addAccountExplicitly(account, "Add Password If you Like", userData);

/**
* This is a crucial step. If you just call above statement and leave as it
* is, AccountAuthenticator getAuthToken will be called
* and there you have to have a proper mechanism to get Auth Token from server
* Right now we are not using it. Instead we are directly
* setting the auth token here
* As per documentation, it says that it caches token here and can be
* retrieved mAccountManager.peekAuthToken(account, ACCOUNT_AUTH_TYPE);
* but , while calling mAccountManager.peekAuthToken(account, ACCOUNT_AUTH_TYPE);
* there isn't any cached token
* And lot of other implementation have saved password and accessed
* password from AccountAuthenticator getAuthToken...
* So for right now , we are saving auth token on user data
* above*/
mAccountManager.setAuthToken(account, user.authToken, ACCOUNT_AUTH_TYPE);
}

/**
* Removing all the accounts of ACCOUNT_TYPE
*/
public void removeAllAccounts() {
final List<Account> availableAccounts = getAccounts();
for (Account account : availableAccounts) {
mAccountManager.removeAccount(account, null, null);
}
}

/**
* Method to retrieve information
* saved on Account if available
*/
public User getCurrentUser() {
User user = null;

final List<Account> availableAccounts = getAccounts();
if (availableAccounts.size() > 0) {
// Right now we are only using a single account i.e. only one user per app
Account account = availableAccounts.get(0);
user = new User();
user.email = mAccountManager.getUserData(account, USER_EMAIL);
user.name = mAccountManager.getUserData(account, USER_NAME);
user.uname = mAccountManager.getUserData(account, USER_UNAME);
user.authToken = mAccountManager.getUserData(account, USER_AUTH_TOKEN);
}

return user;
}
}
27 changes: 27 additions & 0 deletions app/src/main/java/com/meg7/soas/account/notes.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
Logic Implementation

1: Sign In/Sign Up Activity (AuthActivity) must extend AccountAuthenticatorActivity, as this activity is launched
whenever Add Account action is called from anywhere
2: AuthActivity is called from AccountAuthenticator class , where there are different methods for different
account action. These methods are to be defined by ourselves as per our need
3: AccountAuthenticator class is called from AccountAuthenticatorService, whenever Add Account action or
action related to Accounts is called
So Add Account Action Called --> AccountAuthenticatorService listens --> AccountAuthenticator class
is called --> AuthActivity is called

4: For all these classes to function properly, it should be defined on manifest file along with xml/
account_authenticator.xml

5: SoasAccountManager is a simple class which lists all the accounts,delete all the accounts
and add User to the account

Sites with more implementation of AccountManager

http://www.fussylogic.co.uk/blog/?p=1035
http://udinic.wordpress.com/2013/04/24/write-your-own-android-authenticator/
https://github.com/chrisbanes/philm/tree/master/app/src/main/java/app/philm/in/account
https://alandjackson.wordpress.com/2011/01/05/android-tutorial-snippetsauthenticating-accounts/
http://www.jiahaoliuliu.com/2012/05/android-account-manager-part-i.html
http://developer.android.com/training/sync-adapters/creating-authenticator.html#DeclareAuthenticator
http://alvinalexander.com/java/jwarehouse/apps-for-android/SampleSyncAdapter/src/com/example/android/samplesync/authenticator/Authenticator.java.shtml
https://gitorious.org/rowboat/development/source/00bf0f0296b6691a9ed93fa46eccf316f7b0222e:samples/SampleSyncAdapter/src/com/example/android/samplesync/authenticator/Authenticator.java
13 changes: 13 additions & 0 deletions app/src/main/java/com/meg7/soas/data/User.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.meg7.soas.data;

/**
* @author Santosh Dhakal
*/
public class User {

public String email;
public String authToken;
public String name;
public String uname;

}
Loading

0 comments on commit 8818c35

Please sign in to comment.