diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/Constants.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/Constants.java index f233a5d4e..49f92bfff 100644 --- a/samples/SampleSyncAdapter/src/com/example/android/samplesync/Constants.java +++ b/samples/SampleSyncAdapter/src/com/example/android/samplesync/Constants.java @@ -13,7 +13,6 @@ * License for the specific language governing permissions and limitations under * the License. */ - package com.example.android.samplesync; public class Constants { @@ -26,7 +25,5 @@ public class Constants { /** * Authtoken type string. */ - public static final String AUTHTOKEN_TYPE = - "com.example.android.samplesync"; - + public static final String AUTHTOKEN_TYPE = "com.example.android.samplesync"; } diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/authenticator/AuthenticationService.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/authenticator/AuthenticationService.java index b8a903ddb..2c163be66 100644 --- a/samples/SampleSyncAdapter/src/com/example/android/samplesync/authenticator/AuthenticationService.java +++ b/samples/SampleSyncAdapter/src/com/example/android/samplesync/authenticator/AuthenticationService.java @@ -13,7 +13,6 @@ * License for the specific language governing permissions and limitations under * the License. */ - package com.example.android.samplesync.authenticator; import android.app.Service; @@ -26,7 +25,9 @@ import android.util.Log; * and returns its IBinder. */ public class AuthenticationService extends Service { + private static final String TAG = "AuthenticationService"; + private Authenticator mAuthenticator; @Override @@ -47,9 +48,8 @@ public class AuthenticationService extends Service { @Override public IBinder onBind(Intent intent) { if (Log.isLoggable(TAG, Log.VERBOSE)) { - Log.v(TAG, - "getBinder()... returning the AccountAuthenticator binder for intent " - + intent); + Log.v(TAG, "getBinder()... returning the AccountAuthenticator binder for intent " + + intent); } return mAuthenticator.getIBinder(); } diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/authenticator/Authenticator.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/authenticator/Authenticator.java index 29613a948..0c79c5e99 100644 --- a/samples/SampleSyncAdapter/src/com/example/android/samplesync/authenticator/Authenticator.java +++ b/samples/SampleSyncAdapter/src/com/example/android/samplesync/authenticator/Authenticator.java @@ -13,7 +13,6 @@ * License for the specific language governing permissions and limitations under * the License. */ - package com.example.android.samplesync.authenticator; import android.accounts.AbstractAccountAuthenticator; @@ -33,6 +32,7 @@ import com.example.android.samplesync.client.NetworkUtilities; * authenticating accounts in the com.example.android.samplesync domain. */ class Authenticator extends AbstractAccountAuthenticator { + // Authentication Service context private final Context mContext; @@ -41,34 +41,25 @@ class Authenticator extends AbstractAccountAuthenticator { mContext = context; } - /** - * {@inheritDoc} - */ @Override - public Bundle addAccount(AccountAuthenticatorResponse response, - String accountType, String authTokenType, String[] requiredFeatures, - Bundle options) { + public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, + String authTokenType, String[] requiredFeatures, Bundle options) { + final Intent intent = new Intent(mContext, AuthenticatorActivity.class); - intent.putExtra(AuthenticatorActivity.PARAM_AUTHTOKEN_TYPE, - authTokenType); - intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, - response); + intent.putExtra(AuthenticatorActivity.PARAM_AUTHTOKEN_TYPE, authTokenType); + intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response); final Bundle bundle = new Bundle(); bundle.putParcelable(AccountManager.KEY_INTENT, intent); return bundle; } - /** - * {@inheritDoc} - */ @Override - public Bundle confirmCredentials(AccountAuthenticatorResponse response, - Account account, Bundle options) { + public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account, + Bundle options) { + if (options != null && options.containsKey(AccountManager.KEY_PASSWORD)) { - final String password = - options.getString(AccountManager.KEY_PASSWORD); - final boolean verified = - onlineConfirmPassword(account.name, password); + final String password = options.getString(AccountManager.KEY_PASSWORD); + final boolean verified = onlineConfirmPassword(account.name, password); final Bundle result = new Bundle(); result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, verified); return result; @@ -76,45 +67,35 @@ class Authenticator extends AbstractAccountAuthenticator { // Launch AuthenticatorActivity to confirm credentials final Intent intent = new Intent(mContext, AuthenticatorActivity.class); intent.putExtra(AuthenticatorActivity.PARAM_USERNAME, account.name); - intent.putExtra(AuthenticatorActivity.PARAM_CONFIRMCREDENTIALS, true); - intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, - response); + intent.putExtra(AuthenticatorActivity.PARAM_CONFIRM_CREDENTIALS, true); + intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response); final Bundle bundle = new Bundle(); bundle.putParcelable(AccountManager.KEY_INTENT, intent); return bundle; } - /** - * {@inheritDoc} - */ @Override - public Bundle editProperties(AccountAuthenticatorResponse response, - String accountType) { + public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) { throw new UnsupportedOperationException(); } - /** - * {@inheritDoc} - */ @Override - public Bundle getAuthToken(AccountAuthenticatorResponse response, - Account account, String authTokenType, Bundle loginOptions) { + public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, + String authTokenType, Bundle loginOptions) { + if (!authTokenType.equals(Constants.AUTHTOKEN_TYPE)) { final Bundle result = new Bundle(); - result.putString(AccountManager.KEY_ERROR_MESSAGE, - "invalid authTokenType"); + result.putString(AccountManager.KEY_ERROR_MESSAGE, "invalid authTokenType"); return result; } final AccountManager am = AccountManager.get(mContext); final String password = am.getPassword(account); if (password != null) { - final boolean verified = - onlineConfirmPassword(account.name, password); + final boolean verified = onlineConfirmPassword(account.name, password); if (verified) { final Bundle result = new Bundle(); result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name); - result.putString(AccountManager.KEY_ACCOUNT_TYPE, - Constants.ACCOUNT_TYPE); + result.putString(AccountManager.KEY_ACCOUNT_TYPE, Constants.ACCOUNT_TYPE); result.putString(AccountManager.KEY_AUTHTOKEN, password); return result; } @@ -123,33 +104,25 @@ class Authenticator extends AbstractAccountAuthenticator { // Activity that will prompt the user for the password. final Intent intent = new Intent(mContext, AuthenticatorActivity.class); intent.putExtra(AuthenticatorActivity.PARAM_USERNAME, account.name); - intent.putExtra(AuthenticatorActivity.PARAM_AUTHTOKEN_TYPE, - authTokenType); - intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, - response); + intent.putExtra(AuthenticatorActivity.PARAM_AUTHTOKEN_TYPE, authTokenType); + intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response); final Bundle bundle = new Bundle(); bundle.putParcelable(AccountManager.KEY_INTENT, intent); return bundle; } - /** - * {@inheritDoc} - */ @Override public String getAuthTokenLabel(String authTokenType) { - if (authTokenType.equals(Constants.AUTHTOKEN_TYPE)) { + if (Constants.AUTHTOKEN_TYPE.equals(authTokenType)) { return mContext.getString(R.string.label); } return null; - } - /** - * {@inheritDoc} - */ @Override - public Bundle hasFeatures(AccountAuthenticatorResponse response, - Account account, String[] features) { + public Bundle hasFeatures(AccountAuthenticatorResponse response, Account account, + String[] features) { + final Bundle result = new Bundle(); result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false); return result; @@ -159,24 +132,20 @@ class Authenticator extends AbstractAccountAuthenticator { * Validates user's password on the server */ private boolean onlineConfirmPassword(String username, String password) { - return NetworkUtilities.authenticate(username, password, - null/* Handler */, null/* Context */); + return NetworkUtilities + .authenticate(username, password, null/* Handler */, null/* Context */); } - /** - * {@inheritDoc} - */ @Override - public Bundle updateCredentials(AccountAuthenticatorResponse response, - Account account, String authTokenType, Bundle loginOptions) { + public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account, + String authTokenType, Bundle loginOptions) { + final Intent intent = new Intent(mContext, AuthenticatorActivity.class); intent.putExtra(AuthenticatorActivity.PARAM_USERNAME, account.name); - intent.putExtra(AuthenticatorActivity.PARAM_AUTHTOKEN_TYPE, - authTokenType); - intent.putExtra(AuthenticatorActivity.PARAM_CONFIRMCREDENTIALS, false); + intent.putExtra(AuthenticatorActivity.PARAM_AUTHTOKEN_TYPE, authTokenType); + intent.putExtra(AuthenticatorActivity.PARAM_CONFIRM_CREDENTIALS, false); final Bundle bundle = new Bundle(); bundle.putParcelable(AccountManager.KEY_INTENT, intent); return bundle; } - } diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/authenticator/AuthenticatorActivity.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/authenticator/AuthenticatorActivity.java index 779e89432..4e1ee2a75 100644 --- a/samples/SampleSyncAdapter/src/com/example/android/samplesync/authenticator/AuthenticatorActivity.java +++ b/samples/SampleSyncAdapter/src/com/example/android/samplesync/authenticator/AuthenticatorActivity.java @@ -13,7 +13,6 @@ * License for the specific language governing permissions and limitations under * the License. */ - package com.example.android.samplesync.authenticator; import android.accounts.Account; @@ -42,16 +41,28 @@ import com.example.android.samplesync.client.NetworkUtilities; * Activity which displays login screen to the user. */ public class AuthenticatorActivity extends AccountAuthenticatorActivity { - public static final String PARAM_CONFIRMCREDENTIALS = "confirmCredentials"; + + /** The Intent flag to confirm credentials. **/ + public static final String PARAM_CONFIRM_CREDENTIALS = "confirmCredentials"; + + /** The Intent extra to store password. **/ public static final String PARAM_PASSWORD = "password"; + + /** The Intent extra to store username. **/ public static final String PARAM_USERNAME = "username"; + + /** The Intent extra to store authtoken type. **/ public static final String PARAM_AUTHTOKEN_TYPE = "authtokenType"; + /** The tag used to log to adb console. **/ private static final String TAG = "AuthenticatorActivity"; private AccountManager mAccountManager; + private Thread mAuthThread; + private String mAuthtoken; + private String mAuthtokenType; /** @@ -62,14 +73,18 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity { /** for posting authentication attempts back to UI thread */ private final Handler mHandler = new Handler(); + private TextView mMessage; + private String mPassword; + private EditText mPasswordEdit; /** Was the original caller asking for an entirely new account? */ protected boolean mRequestNewAccount = false; private String mUsername; + private EditText mUsernameEdit; /** @@ -77,6 +92,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity { */ @Override public void onCreate(Bundle icicle) { + Log.i(TAG, "onCreate(" + icicle + ")"); super.onCreate(icicle); mAccountManager = AccountManager.get(this); @@ -85,19 +101,15 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity { mUsername = intent.getStringExtra(PARAM_USERNAME); mAuthtokenType = intent.getStringExtra(PARAM_AUTHTOKEN_TYPE); mRequestNewAccount = mUsername == null; - mConfirmCredentials = - intent.getBooleanExtra(PARAM_CONFIRMCREDENTIALS, false); - + mConfirmCredentials = intent.getBooleanExtra(PARAM_CONFIRM_CREDENTIALS, false); Log.i(TAG, " request new: " + mRequestNewAccount); requestWindowFeature(Window.FEATURE_LEFT_ICON); setContentView(R.layout.login_activity); getWindow().setFeatureDrawableResource(Window.FEATURE_LEFT_ICON, android.R.drawable.ic_dialog_alert); - mMessage = (TextView) findViewById(R.id.message); mUsernameEdit = (EditText) findViewById(R.id.username_edit); mPasswordEdit = (EditText) findViewById(R.id.password_edit); - mUsernameEdit.setText(mUsername); mMessage.setText(getMessage()); } @@ -152,7 +164,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity { * * @param the confirmCredentials result. */ - protected void finishConfirmCredentials(boolean result) { + private void finishConfirmCredentials(boolean result) { Log.i(TAG, "finishConfirmCredentials()"); final Account account = new Account(mUsername, Constants.ACCOUNT_TYPE); mAccountManager.setPassword(account, mPassword); @@ -164,7 +176,6 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity { } /** - * * Called when response is received from the server for authentication * request. See onAuthenticationResult(). Sets the * AccountAuthenticatorResult which is sent back to the caller. Also sets @@ -172,26 +183,22 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity { * * @param the confirmCredentials result. */ + private void finishLogin() { - protected void finishLogin() { Log.i(TAG, "finishLogin()"); final Account account = new Account(mUsername, Constants.ACCOUNT_TYPE); - if (mRequestNewAccount) { mAccountManager.addAccountExplicitly(account, mPassword, null); // Set contacts sync for this account. - ContentResolver.setSyncAutomatically(account, - ContactsContract.AUTHORITY, true); + ContentResolver.setSyncAutomatically(account, ContactsContract.AUTHORITY, true); } else { mAccountManager.setPassword(account, mPassword); } final Intent intent = new Intent(); mAuthtoken = mPassword; intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, mUsername); - intent - .putExtra(AccountManager.KEY_ACCOUNT_TYPE, Constants.ACCOUNT_TYPE); - if (mAuthtokenType != null - && mAuthtokenType.equals(Constants.AUTHTOKEN_TYPE)) { + intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE, Constants.ACCOUNT_TYPE); + if (mAuthtokenType != null && mAuthtokenType.equals(Constants.AUTHTOKEN_TYPE)) { intent.putExtra(AccountManager.KEY_AUTHTOKEN, mAuthtoken); } setAccountAuthenticatorResult(intent.getExtras()); @@ -202,7 +209,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity { /** * Hides the progress UI for a lengthy operation. */ - protected void hideProgress() { + private void hideProgress() { dismissDialog(0); } @@ -210,6 +217,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity { * Called when the authentication process completes (see attemptLogin()). */ public void onAuthenticationResult(boolean result) { + Log.i(TAG, "onAuthenticationResult(" + result + ")"); // Hide the progress dialog hideProgress(); @@ -223,14 +231,12 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity { Log.e(TAG, "onAuthenticationResult: failed to authenticate"); if (mRequestNewAccount) { // "Please enter a valid username/password. - mMessage - .setText(getText(R.string.login_activity_loginfail_text_both)); + mMessage.setText(getText(R.string.login_activity_loginfail_text_both)); } else { // "Please enter a valid password." (Used when the // account is already in the database but the password // doesn't work.) - mMessage - .setText(getText(R.string.login_activity_loginfail_text_pwonly)); + mMessage.setText(getText(R.string.login_activity_loginfail_text_pwonly)); } } } @@ -243,8 +249,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity { if (TextUtils.isEmpty(mUsername)) { // If no username, then we ask the user to log in using an // appropriate service. - final CharSequence msg = - getText(R.string.login_activity_newaccount_text); + final CharSequence msg = getText(R.string.login_activity_newaccount_text); return msg; } if (TextUtils.isEmpty(mPassword)) { @@ -257,7 +262,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity { /** * Shows the progress UI for a lengthy operation. */ - protected void showProgress() { + private void showProgress() { showDialog(0); } } diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/client/NetworkUtilities.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/client/NetworkUtilities.java index 9d2b66691..29e3c9b89 100644 --- a/samples/SampleSyncAdapter/src/com/example/android/samplesync/client/NetworkUtilities.java +++ b/samples/SampleSyncAdapter/src/com/example/android/samplesync/client/NetworkUtilities.java @@ -13,7 +13,6 @@ * License for the specific language governing permissions and limitations under * the License. */ - package com.example.android.samplesync.client; import android.accounts.Account; @@ -52,21 +51,36 @@ import java.util.TimeZone; /** * Provides utility methods for communicating with the server. */ -public class NetworkUtilities { +final public class NetworkUtilities { + + /** The tag used to log to adb console. **/ private static final String TAG = "NetworkUtilities"; - public static final String PARAM_USERNAME = "username"; + + /** The Intent extra to store password. **/ public static final String PARAM_PASSWORD = "password"; + + /** The Intent extra to store username. **/ + public static final String PARAM_USERNAME = "username"; + public static final String PARAM_UPDATED = "timestamp"; + public static final String USER_AGENT = "AuthenticationService/1.0"; - public static final int REGISTRATION_TIMEOUT = 30 * 1000; // ms - public static final String BASE_URL = - "https://samplesyncadapter.appspot.com"; + + public static final int REGISTRATION_TIMEOUT_MS = 30 * 1000; // ms + + public static final String BASE_URL = "https://samplesyncadapter.appspot.com"; + public static final String AUTH_URI = BASE_URL + "/auth"; - public static final String FETCH_FRIEND_UPDATES_URI = - BASE_URL + "/fetch_friend_updates"; + + public static final String FETCH_FRIEND_UPDATES_URI = BASE_URL + "/fetch_friend_updates"; + public static final String FETCH_STATUS_URI = BASE_URL + "/fetch_status"; + private static HttpClient mHttpClient; + private NetworkUtilities() { + } + /** * Configures the httpClient to connect to the URL provided. */ @@ -74,10 +88,9 @@ public class NetworkUtilities { if (mHttpClient == null) { mHttpClient = new DefaultHttpClient(); final HttpParams params = mHttpClient.getParams(); - HttpConnectionParams.setConnectionTimeout(params, - REGISTRATION_TIMEOUT); - HttpConnectionParams.setSoTimeout(params, REGISTRATION_TIMEOUT); - ConnManagerParams.setTimeout(params, REGISTRATION_TIMEOUT); + HttpConnectionParams.setConnectionTimeout(params, REGISTRATION_TIMEOUT_M); + HttpConnectionParams.setSoTimeout(params, REGISTRATION_TIMEOUT_MS); + ConnManagerParams.setTimeout(params, REGISTRATION_TIMEOUT_MS); } } @@ -94,7 +107,6 @@ public class NetworkUtilities { try { runnable.run(); } finally { - } } }; @@ -113,10 +125,10 @@ public class NetworkUtilities { * @return boolean The boolean result indicating whether the user was * successfully authenticated. */ - public static boolean authenticate(String username, String password, - Handler handler, final Context context) { - final HttpResponse resp; + public static boolean authenticate(String username, String password, Handler handler, + final Context context) { + final HttpResponse resp; final ArrayList params = new ArrayList(); params.add(new BasicNameValuePair(PARAM_USERNAME, username)); params.add(new BasicNameValuePair(PARAM_PASSWORD, password)); @@ -131,7 +143,6 @@ public class NetworkUtilities { post.addHeader(entity.getContentType()); post.setEntity(entity); maybeCreateHttpClient(); - try { resp = mHttpClient.execute(post); if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { @@ -189,8 +200,9 @@ public class NetworkUtilities { * @param context The caller Activity's context * @return Thread The thread on which the network mOperations are executed. */ - public static Thread attemptAuth(final String username, - final String password, final Handler handler, final Context context) { + public static Thread attemptAuth(final String username, final String password, + final Handler handler, final Context context) { + final Runnable runnable = new Runnable() { public void run() { authenticate(username, password, handler, context); @@ -208,32 +220,27 @@ public class NetworkUtilities { * @param lastUpdated The last time that sync was performed * @return list The list of updates received from the server. */ - public static List fetchFriendUpdates(Account account, - String authtoken, Date lastUpdated) throws JSONException, - ParseException, IOException, AuthenticationException { + public static List fetchFriendUpdates(Account account, String authtoken, Date lastUpdated) + throws JSONException, ParseException, IOException, AuthenticationException { + final ArrayList friendList = new ArrayList(); final ArrayList params = new ArrayList(); params.add(new BasicNameValuePair(PARAM_USERNAME, account.name)); params.add(new BasicNameValuePair(PARAM_PASSWORD, authtoken)); if (lastUpdated != null) { - final SimpleDateFormat formatter = - new SimpleDateFormat("yyyy/MM/dd HH:mm"); + final SimpleDateFormat formatter = new SimpleDateFormat("yyyy/MM/dd HH:mm"); formatter.setTimeZone(TimeZone.getTimeZone("UTC")); - params.add(new BasicNameValuePair(PARAM_UPDATED, formatter - .format(lastUpdated))); + params.add(new BasicNameValuePair(PARAM_UPDATED, formatter.format(lastUpdated))); } Log.i(TAG, params.toString()); - HttpEntity entity = null; entity = new UrlEncodedFormEntity(params); final HttpPost post = new HttpPost(FETCH_FRIEND_UPDATES_URI); post.addHeader(entity.getContentType()); post.setEntity(entity); maybeCreateHttpClient(); - final HttpResponse resp = mHttpClient.execute(post); final String response = EntityUtils.toString(resp.getEntity()); - if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { // Succesfully connected to the samplesyncadapter server and // authenticated. @@ -245,12 +252,10 @@ public class NetworkUtilities { } } else { if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_UNAUTHORIZED) { - Log.e(TAG, - "Authentication exception in fetching remote contacts"); + Log.e(TAG, "Authentication exception in fetching remote contacts"); throw new AuthenticationException(); } else { - Log.e(TAG, "Server error in fetching remote contacts: " - + resp.getStatusLine()); + Log.e(TAG, "Server error in fetching remote contacts: " + resp.getStatusLine()); throw new IOException(); } } @@ -265,24 +270,21 @@ public class NetworkUtilities { * account * @return list The list of status messages received from the server. */ - public static List fetchFriendStatuses(Account account, - String authtoken) throws JSONException, ParseException, IOException, - AuthenticationException { + public static List fetchFriendStatuses(Account account, String authtoken) + throws JSONException, ParseException, IOException, AuthenticationException { + final ArrayList statusList = new ArrayList(); final ArrayList params = new ArrayList(); params.add(new BasicNameValuePair(PARAM_USERNAME, account.name)); params.add(new BasicNameValuePair(PARAM_PASSWORD, authtoken)); - HttpEntity entity = null; entity = new UrlEncodedFormEntity(params); final HttpPost post = new HttpPost(FETCH_STATUS_URI); post.addHeader(entity.getContentType()); post.setEntity(entity); maybeCreateHttpClient(); - final HttpResponse resp = mHttpClient.execute(post); final String response = EntityUtils.toString(resp.getEntity()); - if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { // Succesfully connected to the samplesyncadapter server and // authenticated. @@ -293,8 +295,7 @@ public class NetworkUtilities { } } else { if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_UNAUTHORIZED) { - Log.e(TAG, - "Authentication exception in fetching friend status list"); + Log.e(TAG, "Authentication exception in fetching friend status list"); throw new AuthenticationException(); } else { Log.e(TAG, "Server error in fetching friend status list"); @@ -303,5 +304,4 @@ public class NetworkUtilities { } return statusList; } - } diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/client/User.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/client/User.java index 6ce9b3fe6..217a383d8 100644 --- a/samples/SampleSyncAdapter/src/com/example/android/samplesync/client/User.java +++ b/samples/SampleSyncAdapter/src/com/example/android/samplesync/client/User.java @@ -13,7 +13,6 @@ * License for the specific language governing permissions and limitations under * the License. */ - package com.example.android.samplesync.client; import android.util.Log; @@ -23,16 +22,24 @@ import org.json.JSONObject; /** * Represents a sample SyncAdapter user */ -public class User { +final public class User { private final String mUserName; + private final String mFirstName; + private final String mLastName; + private final String mCellPhone; + private final String mOfficePhone; + private final String mHomePhone; + private final String mEmail; + private final boolean mDeleted; + private final int mUserId; public int getUserId() { @@ -71,9 +78,9 @@ public class User { return mDeleted; } - public User(String name, String firstName, String lastName, - String cellPhone, String officePhone, String homePhone, String email, - Boolean deleted, Integer userId) { + private User(String name, String firstName, String lastName, String cellPhone, + String officePhone, String homePhone, String email, Boolean deleted, Integer userId) { + mUserName = name; mFirstName = firstName; mLastName = lastName; @@ -92,34 +99,33 @@ public class User { * @return user The new instance of Voiper user created from the JSON data. */ public static User valueOf(JSONObject user) { + try { final String userName = user.getString("u"); final String firstName = user.has("f") ? user.getString("f") : null; final String lastName = user.has("l") ? user.getString("l") : null; final String cellPhone = user.has("m") ? user.getString("m") : null; - final String officePhone = - user.has("o") ? user.getString("o") : null; + final String officePhone = user.has("o") ? user.getString("o") : null; final String homePhone = user.has("h") ? user.getString("h") : null; final String email = user.has("e") ? user.getString("e") : null; - final boolean deleted = - user.has("d") ? user.getBoolean("d") : false; + final boolean deleted = user.has("d") ? user.getBoolean("d") : false; final int userId = user.getInt("i"); - return new User(userName, firstName, lastName, cellPhone, - officePhone, homePhone, email, deleted, userId); + return new User(userName, firstName, lastName, cellPhone, officePhone, homePhone, + email, deleted, userId); } catch (final Exception ex) { Log.i("User", "Error parsing JSON user object" + ex.toString()); - } return null; - } /** * Represents the User's status messages * */ - public static class Status { + final public static class Status { + private final Integer mUserId; + private final String mStatus; public int getUserId() { @@ -146,5 +152,4 @@ public class User { return null; } } - } diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/BatchOperation.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/BatchOperation.java index 509d1516c..0be3daa8b 100644 --- a/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/BatchOperation.java +++ b/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/BatchOperation.java @@ -13,7 +13,6 @@ * License for the specific language governing permissions and limitations under * the License. */ - package com.example.android.samplesync.platform; import android.content.ContentProviderOperation; @@ -29,12 +28,14 @@ import java.util.ArrayList; /** * This class handles execution of batch mOperations on Contacts provider. */ -public class BatchOperation { +final public class BatchOperation { + private final String TAG = "BatchOperation"; private final ContentResolver mResolver; + // List for storing the batch mOperations - ArrayList mOperations; + private final ArrayList mOperations; public BatchOperation(Context context, ContentResolver resolver) { mResolver = resolver; @@ -50,6 +51,7 @@ public class BatchOperation { } public void execute() { + if (mOperations.size() == 0) { return; } @@ -63,5 +65,4 @@ public class BatchOperation { } mOperations.clear(); } - } diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/ContactManager.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/ContactManager.java index 4f71be071..218b165b6 100644 --- a/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/ContactManager.java +++ b/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/ContactManager.java @@ -13,7 +13,6 @@ * License for the specific language governing permissions and limitations under * the License. */ - package com.example.android.samplesync.platform; import android.content.ContentResolver; @@ -41,10 +40,12 @@ import java.util.List; * Class for managing contacts sync related mOperations */ public class ContactManager { + /** * Custom IM protocol used when storing status messages. */ public static final String CUSTOM_IM_PROTOCOL = "SampleSyncAdapter"; + private static final String TAG = "ContactManager"; /** @@ -54,13 +55,12 @@ public class ContactManager { * @param account The username for the account * @param users The list of users */ - public static synchronized void syncContacts(Context context, - String account, List users) { + public static synchronized void syncContacts(Context context, String account, List users) { + long userId; long rawContactId = 0; final ContentResolver resolver = context.getContentResolver(); - final BatchOperation batchOperation = - new BatchOperation(context, resolver); + final BatchOperation batchOperation = new BatchOperation(context, resolver); Log.d(TAG, "In SyncContacts"); for (final User user : users) { userId = user.getUserId(); @@ -69,8 +69,7 @@ public class ContactManager { if (rawContactId != 0) { if (!user.isDeleted()) { // update contact - updateContact(context, resolver, account, user, - rawContactId, batchOperation); + updateContact(context, resolver, account, user, rawContactId, batchOperation); } else { // delete contact deleteContact(context, rawContactId, batchOperation); @@ -98,17 +97,15 @@ public class ContactManager { * @param accountName the username of the logged in user * @param statuses the list of statuses to store */ - public static void insertStatuses(Context context, String username, - List list) { + public static void insertStatuses(Context context, String username, List list) { + final ContentValues values = new ContentValues(); final ContentResolver resolver = context.getContentResolver(); - final BatchOperation batchOperation = - new BatchOperation(context, resolver); + final BatchOperation batchOperation = new BatchOperation(context, resolver); for (final User.Status status : list) { // Look up the user's sample SyncAdapter data row final long userId = status.getUserId(); final long profileId = lookupProfile(resolver, userId); - // Insert the activity into the stream if (profileId > 0) { values.put(StatusUpdates.DATA_ID, profileId); @@ -117,15 +114,11 @@ public class ContactManager { values.put(StatusUpdates.CUSTOM_PROTOCOL, CUSTOM_IM_PROTOCOL); values.put(StatusUpdates.IM_ACCOUNT, username); values.put(StatusUpdates.IM_HANDLE, status.getUserId()); - values.put(StatusUpdates.STATUS_RES_PACKAGE, context - .getPackageName()); + values.put(StatusUpdates.STATUS_RES_PACKAGE, context.getPackageName()); values.put(StatusUpdates.STATUS_ICON, R.drawable.icon); values.put(StatusUpdates.STATUS_LABEL, R.string.label); - - batchOperation - .add(ContactOperations.newInsertCpo( - StatusUpdates.CONTENT_URI, true).withValues(values) - .build()); + batchOperation.add(ContactOperations.newInsertCpo(StatusUpdates.CONTENT_URI, true) + .withValues(values).build()); // A sync adapter should batch operations on multiple contacts, // because it will make a dramatic performance difference. if (batchOperation.size() >= 50) { @@ -143,16 +136,16 @@ public class ContactManager { * @param accountName the account the contact belongs to * @param user the sample SyncAdapter User object */ - private static void addContact(Context context, String accountName, - User user, BatchOperation batchOperation) { + private static void addContact(Context context, String accountName, User user, + BatchOperation batchOperation) { + // Put the data in the contacts provider final ContactOperations contactOp = - ContactOperations.createNewContact(context, user.getUserId(), - accountName, batchOperation); - contactOp.addName(user.getFirstName(), user.getLastName()).addEmail( - user.getEmail()).addPhone(user.getCellPhone(), Phone.TYPE_MOBILE) - .addPhone(user.getHomePhone(), Phone.TYPE_OTHER).addProfileAction( - user.getUserId()); + ContactOperations.createNewContact(context, user.getUserId(), accountName, + batchOperation); + contactOp.addName(user.getFirstName(), user.getLastName()).addEmail(user.getEmail()) + .addPhone(user.getCellPhone(), Phone.TYPE_MOBILE).addPhone(user.getHomePhone(), + Phone.TYPE_OTHER).addProfileAction(user.getUserId()); } /** @@ -165,76 +158,57 @@ public class ContactManager { * @param rawContactId the unique Id for this rawContact in contacts * provider */ - private static void updateContact(Context context, - ContentResolver resolver, String accountName, User user, - long rawContactId, BatchOperation batchOperation) { + private static void updateContact(Context context, ContentResolver resolver, + String accountName, User user, long rawContactId, BatchOperation batchOperation) { + Uri uri; String cellPhone = null; String otherPhone = null; String email = null; - final Cursor c = - resolver.query(Data.CONTENT_URI, DataQuery.PROJECTION, - DataQuery.SELECTION, + resolver.query(Data.CONTENT_URI, DataQuery.PROJECTION, DataQuery.SELECTION, new String[] {String.valueOf(rawContactId)}, null); final ContactOperations contactOp = - ContactOperations.updateExistingContact(context, rawContactId, - batchOperation); - + ContactOperations.updateExistingContact(context, rawContactId, batchOperation); try { while (c.moveToNext()) { final long id = c.getLong(DataQuery.COLUMN_ID); final String mimeType = c.getString(DataQuery.COLUMN_MIMETYPE); uri = ContentUris.withAppendedId(Data.CONTENT_URI, id); - if (mimeType.equals(StructuredName.CONTENT_ITEM_TYPE)) { - final String lastName = - c.getString(DataQuery.COLUMN_FAMILY_NAME); - final String firstName = - c.getString(DataQuery.COLUMN_GIVEN_NAME); - contactOp.updateName(uri, firstName, lastName, user - .getFirstName(), user.getLastName()); - } - - else if (mimeType.equals(Phone.CONTENT_ITEM_TYPE)) { + final String lastName = c.getString(DataQuery.COLUMN_FAMILY_NAME); + final String firstName = c.getString(DataQuery.COLUMN_GIVEN_NAME); + contactOp.updateName(uri, firstName, lastName, user.getFirstName(), user + .getLastName()); + } else if (mimeType.equals(Phone.CONTENT_ITEM_TYPE)) { final int type = c.getInt(DataQuery.COLUMN_PHONE_TYPE); - if (type == Phone.TYPE_MOBILE) { cellPhone = c.getString(DataQuery.COLUMN_PHONE_NUMBER); - contactOp.updatePhone(cellPhone, user.getCellPhone(), - uri); + contactOp.updatePhone(cellPhone, user.getCellPhone(), uri); } else if (type == Phone.TYPE_OTHER) { otherPhone = c.getString(DataQuery.COLUMN_PHONE_NUMBER); - contactOp.updatePhone(otherPhone, user.getHomePhone(), - uri); + contactOp.updatePhone(otherPhone, user.getHomePhone(), uri); } - } - - else if (Data.MIMETYPE.equals(Email.CONTENT_ITEM_TYPE)) { + } else if (Data.MIMETYPE.equals(Email.CONTENT_ITEM_TYPE)) { email = c.getString(DataQuery.COLUMN_EMAIL_ADDRESS); contactOp.updateEmail(user.getEmail(), email, uri); - } } // while } finally { c.close(); } - // Add the cell phone, if present and not updated above if (cellPhone == null) { contactOp.addPhone(user.getCellPhone(), Phone.TYPE_MOBILE); } - // Add the other phone, if present and not updated above if (otherPhone == null) { contactOp.addPhone(user.getHomePhone(), Phone.TYPE_OTHER); } - // Add the email address, if present and not updated above if (email == null) { contactOp.addEmail(user.getEmail()); } - } /** @@ -246,9 +220,9 @@ public class ContactManager { */ private static void deleteContact(Context context, long rawContactId, BatchOperation batchOperation) { + batchOperation.add(ContactOperations.newDeleteCpo( - ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId), - true).build()); + ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId), true).build()); } /** @@ -260,11 +234,11 @@ public class ContactManager { * @return the RawContact id, or 0 if not found */ private static long lookupRawContact(ContentResolver resolver, long userId) { + long authorId = 0; final Cursor c = - resolver.query(RawContacts.CONTENT_URI, UserIdQuery.PROJECTION, - UserIdQuery.SELECTION, new String[] {String.valueOf(userId)}, - null); + resolver.query(RawContacts.CONTENT_URI, UserIdQuery.PROJECTION, UserIdQuery.SELECTION, + new String[] {String.valueOf(userId)}, null); try { if (c.moveToFirst()) { authorId = c.getLong(UserIdQuery.COLUMN_ID); @@ -286,11 +260,11 @@ public class ContactManager { * @return the profile Data row id, or 0 if not found */ private static long lookupProfile(ContentResolver resolver, long userId) { + long profileId = 0; final Cursor c = - resolver.query(Data.CONTENT_URI, ProfileQuery.PROJECTION, - ProfileQuery.SELECTION, new String[] {String.valueOf(userId)}, - null); + resolver.query(Data.CONTENT_URI, ProfileQuery.PROJECTION, ProfileQuery.SELECTION, + new String[] {String.valueOf(userId)}, null); try { if (c != null && c.moveToFirst()) { profileId = c.getLong(ProfileQuery.COLUMN_ID); @@ -307,22 +281,30 @@ public class ContactManager { * Constants for a query to find a contact given a sample SyncAdapter user * ID. */ - private interface ProfileQuery { + final private static class ProfileQuery { + + private ProfileQuery() { + } + public final static String[] PROJECTION = new String[] {Data._ID}; public final static int COLUMN_ID = 0; public static final String SELECTION = - Data.MIMETYPE + "='" + SampleSyncAdapterColumns.MIME_PROFILE - + "' AND " + SampleSyncAdapterColumns.DATA_PID + "=?"; + Data.MIMETYPE + "='" + SampleSyncAdapterColumns.MIME_PROFILE + "' AND " + + SampleSyncAdapterColumns.DATA_PID + "=?"; } + /** * Constants for a query to find a contact given a sample SyncAdapter user * ID. */ - private interface UserIdQuery { - public final static String[] PROJECTION = - new String[] {RawContacts._ID}; + final private static class UserIdQuery { + + private UserIdQuery() { + } + + public final static String[] PROJECTION = new String[] {RawContacts._ID}; public final static int COLUMN_ID = 0; @@ -334,21 +316,34 @@ public class ContactManager { /** * Constants for a query to get contact data for a given rawContactId */ - private interface DataQuery { + final private static class DataQuery { + + private DataQuery() { + } + public static final String[] PROJECTION = - new String[] {Data._ID, Data.MIMETYPE, Data.DATA1, Data.DATA2, - Data.DATA3,}; + new String[] {Data._ID, Data.MIMETYPE, Data.DATA1, Data.DATA2, Data.DATA3,}; public static final int COLUMN_ID = 0; + public static final int COLUMN_MIMETYPE = 1; + public static final int COLUMN_DATA1 = 2; + public static final int COLUMN_DATA2 = 3; + public static final int COLUMN_DATA3 = 4; + public static final int COLUMN_PHONE_NUMBER = COLUMN_DATA1; + public static final int COLUMN_PHONE_TYPE = COLUMN_DATA2; + public static final int COLUMN_EMAIL_ADDRESS = COLUMN_DATA1; + public static final int COLUMN_EMAIL_TYPE = COLUMN_DATA2; + public static final int COLUMN_GIVEN_NAME = COLUMN_DATA2; + public static final int COLUMN_FAMILY_NAME = COLUMN_DATA3; public static final String SELECTION = Data.RAW_CONTACT_ID + "=?"; diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/ContactOperations.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/ContactOperations.java index 9e47f701d..db01f48ae 100644 --- a/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/ContactOperations.java +++ b/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/ContactOperations.java @@ -13,7 +13,6 @@ * License for the specific language governing permissions and limitations under * the License. */ - package com.example.android.samplesync.platform; import android.content.ContentProviderOperation; @@ -38,12 +37,19 @@ import com.example.android.samplesync.R; public class ContactOperations { private final ContentValues mValues; + private ContentProviderOperation.Builder mBuilder; + private final BatchOperation mBatchOperation; + private final Context mContext; + private boolean mYield; + private long mRawContactId; + private int mBackReference; + private boolean mIsNewContact; /** @@ -55,10 +61,10 @@ public class ContactOperations { * @param accountName the username of the current login * @return instance of ContactOperations */ - public static ContactOperations createNewContact(Context context, - int userId, String accountName, BatchOperation batchOperation) { - return new ContactOperations(context, userId, accountName, - batchOperation); + public static ContactOperations createNewContact(Context context, int userId, + String accountName, BatchOperation batchOperation) { + + return new ContactOperations(context, userId, accountName, batchOperation); } /** @@ -69,8 +75,9 @@ public class ContactOperations { * @param rawContactId the unique Id of the existing rawContact * @return instance of ContactOperations */ - public static ContactOperations updateExistingContact(Context context, - long rawContactId, BatchOperation batchOperation) { + public static ContactOperations updateExistingContact(Context context, long rawContactId, + BatchOperation batchOperation) { + return new ContactOperations(context, rawContactId, batchOperation); } @@ -83,19 +90,18 @@ public class ContactOperations { public ContactOperations(Context context, int userId, String accountName, BatchOperation batchOperation) { + this(context, batchOperation); mBackReference = mBatchOperation.size(); mIsNewContact = true; mValues.put(RawContacts.SOURCE_ID, userId); mValues.put(RawContacts.ACCOUNT_TYPE, Constants.ACCOUNT_TYPE); mValues.put(RawContacts.ACCOUNT_NAME, accountName); - mBuilder = - newInsertCpo(RawContacts.CONTENT_URI, true).withValues(mValues); + mBuilder = newInsertCpo(RawContacts.CONTENT_URI, true).withValues(mValues); mBatchOperation.add(mBuilder.build()); } - public ContactOperations(Context context, long rawContactId, - BatchOperation batchOperation) { + public ContactOperations(Context context, long rawContactId, BatchOperation batchOperation) { this(context, batchOperation); mIsNewContact = false; mRawContactId = rawContactId; @@ -109,16 +115,15 @@ public class ContactOperations { * @return instance of ContactOperations */ public ContactOperations addName(String firstName, String lastName) { + mValues.clear(); if (!TextUtils.isEmpty(firstName)) { mValues.put(StructuredName.GIVEN_NAME, firstName); - mValues.put(StructuredName.MIMETYPE, - StructuredName.CONTENT_ITEM_TYPE); + mValues.put(StructuredName.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE); } if (!TextUtils.isEmpty(lastName)) { mValues.put(StructuredName.FAMILY_NAME, lastName); - mValues.put(StructuredName.MIMETYPE, - StructuredName.CONTENT_ITEM_TYPE); + mValues.put(StructuredName.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE); } if (mValues.size() > 0) { addInsertOp(); @@ -188,8 +193,7 @@ public class ContactOperations { * @param uri Uri for the existing raw contact to be updated * @return instance of ContactOperations */ - public ContactOperations updateEmail(String email, String existingEmail, - Uri uri) { + public ContactOperations updateEmail(String email, String existingEmail, Uri uri) { if (!TextUtils.equals(existingEmail, email)) { mValues.clear(); mValues.put(Email.DATA, email); @@ -207,10 +211,11 @@ public class ContactOperations { * @param uri Uri for the existing raw contact to be updated * @return instance of ContactOperations */ - public ContactOperations updateName(Uri uri, String existingFirstName, - String existingLastName, String firstName, String lastName) { - Log.i("ContactOperations", "ef=" + existingFirstName + "el=" - + existingLastName + "f=" + firstName + "l=" + lastName); + public ContactOperations updateName(Uri uri, String existingFirstName, String existingLastName, + String firstName, String lastName) { + + Log.i("ContactOperations", "ef=" + existingFirstName + "el=" + existingLastName + "f=" + + firstName + "l=" + lastName); mValues.clear(); if (!TextUtils.equals(existingFirstName, firstName)) { mValues.put(StructuredName.GIVEN_NAME, firstName); @@ -232,8 +237,7 @@ public class ContactOperations { * @param uri Uri for the existing raw contact to be updated * @return instance of ContactOperations */ - public ContactOperations updatePhone(String existingNumber, String phone, - Uri uri) { + public ContactOperations updatePhone(String existingNumber, String phone, Uri uri) { if (!TextUtils.equals(phone, existingNumber)) { mValues.clear(); mValues.put(Phone.NUMBER, phone); @@ -260,16 +264,14 @@ public class ContactOperations { * Adds an insert operation into the batch */ private void addInsertOp() { + if (!mIsNewContact) { mValues.put(Phone.RAW_CONTACT_ID, mRawContactId); } - mBuilder = - newInsertCpo(addCallerIsSyncAdapterParameter(Data.CONTENT_URI), - mYield); + mBuilder = newInsertCpo(addCallerIsSyncAdapterParameter(Data.CONTENT_URI), mYield); mBuilder.withValues(mValues); if (mIsNewContact) { - mBuilder - .withValueBackReference(Data.RAW_CONTACT_ID, mBackReference); + mBuilder.withValueBackReference(Data.RAW_CONTACT_ID, mBackReference); } mYield = false; mBatchOperation.add(mBuilder.build()); @@ -284,28 +286,23 @@ public class ContactOperations { mBatchOperation.add(mBuilder.build()); } - public static ContentProviderOperation.Builder newInsertCpo(Uri uri, - boolean yield) { - return ContentProviderOperation.newInsert( - addCallerIsSyncAdapterParameter(uri)).withYieldAllowed(yield); + public static ContentProviderOperation.Builder newInsertCpo(Uri uri, boolean yield) { + return ContentProviderOperation.newInsert(addCallerIsSyncAdapterParameter(uri)) + .withYieldAllowed(yield); } - public static ContentProviderOperation.Builder newUpdateCpo(Uri uri, - boolean yield) { - return ContentProviderOperation.newUpdate( - addCallerIsSyncAdapterParameter(uri)).withYieldAllowed(yield); + public static ContentProviderOperation.Builder newUpdateCpo(Uri uri, boolean yield) { + return ContentProviderOperation.newUpdate(addCallerIsSyncAdapterParameter(uri)) + .withYieldAllowed(yield); } - public static ContentProviderOperation.Builder newDeleteCpo(Uri uri, - boolean yield) { - return ContentProviderOperation.newDelete( - addCallerIsSyncAdapterParameter(uri)).withYieldAllowed(yield); - + public static ContentProviderOperation.Builder newDeleteCpo(Uri uri, boolean yield) { + return ContentProviderOperation.newDelete(addCallerIsSyncAdapterParameter(uri)) + .withYieldAllowed(yield); } private static Uri addCallerIsSyncAdapterParameter(Uri uri) { - return uri.buildUpon().appendQueryParameter( - ContactsContract.CALLER_IS_SYNCADAPTER, "true").build(); + return uri.buildUpon().appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true") + .build(); } - } diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/SampleSyncAdapterColumns.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/SampleSyncAdapterColumns.java index bc02325ff..7b60d5bd7 100644 --- a/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/SampleSyncAdapterColumns.java +++ b/samples/SampleSyncAdapter/src/com/example/android/samplesync/platform/SampleSyncAdapterColumns.java @@ -20,7 +20,11 @@ import android.provider.ContactsContract.Data; /* * The standard columns representing contact's info from social apps. */ -public interface SampleSyncAdapterColumns { +public final class SampleSyncAdapterColumns { + + private SampleSyncAdapterColumns() { + } + /** * MIME-type used when storing a profile {@link Data} entry. */ @@ -28,7 +32,8 @@ public interface SampleSyncAdapterColumns { "vnd.android.cursor.item/vnd.samplesyncadapter.profile"; public static final String DATA_PID = Data.DATA1; - public static final String DATA_SUMMARY = Data.DATA2; - public static final String DATA_DETAIL = Data.DATA3; + public static final String DATA_SUMMARY = Data.DATA2; + + public static final String DATA_DETAIL = Data.DATA3; } diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/syncadapter/SyncAdapter.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/syncadapter/SyncAdapter.java index 07525aac7..206189ad5 100644 --- a/samples/SampleSyncAdapter/src/com/example/android/samplesync/syncadapter/SyncAdapter.java +++ b/samples/SampleSyncAdapter/src/com/example/android/samplesync/syncadapter/SyncAdapter.java @@ -13,7 +13,6 @@ * License for the specific language governing permissions and limitations under * the License. */ - package com.example.android.samplesync.syncadapter; import android.accounts.Account; @@ -46,9 +45,11 @@ import java.util.List; * platform ContactOperations provider. */ public class SyncAdapter extends AbstractThreadedSyncAdapter { + private static final String TAG = "SyncAdapter"; private final AccountManager mAccountManager; + private final Context mContext; private Date mLastUpdated; @@ -62,18 +63,17 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter { @Override public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) { + List users; List statuses; String authtoken = null; - try { - // use the account manager to request the credentials - authtoken = - mAccountManager.blockingGetAuthToken(account, - Constants.AUTHTOKEN_TYPE, true /* notifyAuthFailure */); - // fetch updates from the sample service over the cloud - users = - NetworkUtilities.fetchFriendUpdates(account, authtoken, - mLastUpdated); + try { + // use the account manager to request the credentials + authtoken = + mAccountManager + .blockingGetAuthToken(account, Constants.AUTHTOKEN_TYPE, true /* notifyAuthFailure */); + // fetch updates from the sample service over the cloud + users = NetworkUtilities.fetchFriendUpdates(account, authtoken, mLastUpdated); // update the last synced date. mLastUpdated = new Date(); // update platform contacts. @@ -91,8 +91,7 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter { Log.e(TAG, "IOException", e); syncResult.stats.numIoExceptions++; } catch (final AuthenticationException e) { - mAccountManager.invalidateAuthToken(Constants.ACCOUNT_TYPE, - authtoken); + mAccountManager.invalidateAuthToken(Constants.ACCOUNT_TYPE, authtoken); syncResult.stats.numAuthExceptions++; Log.e(TAG, "AuthenticationException", e); } catch (final ParseException e) { diff --git a/samples/SampleSyncAdapter/src/com/example/android/samplesync/syncadapter/SyncService.java b/samples/SampleSyncAdapter/src/com/example/android/samplesync/syncadapter/SyncService.java index 256f91d13..57b7747e7 100644 --- a/samples/SampleSyncAdapter/src/com/example/android/samplesync/syncadapter/SyncService.java +++ b/samples/SampleSyncAdapter/src/com/example/android/samplesync/syncadapter/SyncService.java @@ -13,7 +13,6 @@ * License for the specific language governing permissions and limitations under * the License. */ - package com.example.android.samplesync.syncadapter; import android.app.Service; @@ -26,12 +25,11 @@ import android.os.IBinder; * IBinder. */ public class SyncService extends Service { + private static final Object sSyncAdapterLock = new Object(); + private static SyncAdapter sSyncAdapter = null; - /* - * {@inheritDoc} - */ @Override public void onCreate() { synchronized (sSyncAdapterLock) { @@ -41,9 +39,6 @@ public class SyncService extends Service { } } - /* - * {@inheritDoc} - */ @Override public IBinder onBind(Intent intent) { return sSyncAdapter.getSyncAdapterBinder(); diff --git a/samples/SampleSyncAdapter/tests/src/com/example/android/samplesync/AllTests.java b/samples/SampleSyncAdapter/tests/src/com/example/android/samplesync/AllTests.java new file mode 100644 index 000000000..6f4f006cb --- /dev/null +++ b/samples/SampleSyncAdapter/tests/src/com/example/android/samplesync/AllTests.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.example.android.apis; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import android.test.suitebuilder.TestSuiteBuilder; + +/** + * A test suite containing all tests for SampleSyncAdapter. + * + */ +public class AllTests extends TestSuite { + + public static Test suite() { + return new TestSuiteBuilder(AllTests.class).includeAllPackagesUnderHere().build(); + } +} diff --git a/samples/SampleSyncAdapter/tests/src/com/example/android/samplesync/authenticator/AuthenticatorActivityTest.java b/samples/SampleSyncAdapter/tests/src/com/example/android/samplesync/authenticator/AuthenticatorActivityTest.java new file mode 100644 index 000000000..67d6fda19 --- /dev/null +++ b/samples/SampleSyncAdapter/tests/src/com/example/android/samplesync/authenticator/AuthenticatorActivityTest.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.example.android.samplesync.authenticator; + +import android.app.Activity; +import android.app.Instrumentation; +import android.content.Context; +import android.content.Intent; +import android.test.ActivityInstrumentationTestCase2; +import android.test.suitebuilder.annotation.SmallTest; +import android.view.View; + +/** + * This is a series of unit tests for the {@link AuthenticatorActivity} class. + */ +@SmallTest +public class AuthenticatorActivityTests extends + ActivityInstrumentationTestCase2 { + + private static final int ACTIVITY_WAIT = 10000; + + private Instrumentation mInstrumentation; + + private Context mContext; + + public AuthenticatorActivityTests() { + + super(AuthenticatorActivity.class); + } + + /** + * Common setup code for all tests. Sets up a default launch intent, which + * some tests will use (others will override). + */ + @Override + protected void setUp() throws Exception { + + super.setUp(); + mInstrumentation = this.getInstrumentation(); + mContext = mInstrumentation.getTargetContext(); + } + + @Override + protected void tearDown() throws Exception { + + super.tearDown(); + } + + /** + * Confirm that Login is presented. + */ + @SmallTest + public void testLoginOffered() { + + Instrumentation.ActivityMonitor monitor = + mInstrumentation.addMonitor(AuthenticatorActivity.class.getName(), null, false); + Intent intent = new Intent(mContext, AuthenticatorActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + mInstrumentation.startActivitySync(intent); + Activity activity = mInstrumentation.waitForMonitorWithTimeout(monitor, ACTIVITY_WAIT); + View loginbutton = activity.findViewById(R.id.ok_button); + int expected = View.VISIBLE; + assertEquals(expected, loginbutton.getVisibility()); + } +} diff --git a/samples/SampleSyncAdapter/tests/src/com/example/android/samplesync/client/UserTest.java b/samples/SampleSyncAdapter/tests/src/com/example/android/samplesync/client/UserTest.java new file mode 100644 index 000000000..416234026 --- /dev/null +++ b/samples/SampleSyncAdapter/tests/src/com/example/android/samplesync/client/UserTest.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.example.android.samplesync.client; + +import com.example.android.samplesync.client.User; + +import junit.framework.TestCase; + +import org.json.JSONObject; + +public class UserTest extends TestCase { + + @SmallTest + public void testConstructor() throws Exception { + User user = + new User("mjoshi", "Megha", "Joshi", "1-650-335-5681", "1-650-111-5681", + "1-650-222-5681", "test@google.com", false, 1); + assertEquals("Megha", user.getFirstName()); + assertEquals("Joshi", user.getLastName()); + assertEquals("mjoshi", user.getUserName()); + assertEquals(1, user.getUserId()); + assertEquals("1-650-335-5681", user.getCellPhone()); + assertEquals(false, user.isDeleted()); + } + + @SmallTest + public void testValueOf() throws Exception { + JSONObject jsonObj = new JSONObject(); + jsonObj.put("u", "mjoshi"); + jsonObj.put("f", "Megha"); + jsonObj.put("l", "Joshi"); + jsonObj.put("i", 1); + User user = User.valueOf(jsonObj); + assertEquals("Megha", user.getFirstName()); + assertEquals("Joshi", user.getLastName()); + assertEquals("mjoshi", user.getUserName()); + assertEquals(1, user.getUserId()); + } +}