summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFred Quintana <fredq@google.com>2009-04-23 13:36:27 -0700
committerFred Quintana <fredq@google.com>2009-04-23 15:37:45 -0700
commitd9d2f1140b52fd0c014e9deac59f6000564b7e84 (patch)
tree2c30edce5a148ef94400277f20619c821fd9da94
parent843bbb8597d561c2541f86d1f391ae65261cf743 (diff)
downloadframeworks_base-d9d2f1140b52fd0c014e9deac59f6000564b7e84.zip
frameworks_base-d9d2f1140b52fd0c014e9deac59f6000564b7e84.tar.gz
frameworks_base-d9d2f1140b52fd0c014e9deac59f6000564b7e84.tar.bz2
change the sync framework and users to understand Account
-rw-r--r--api/current.xml141
-rw-r--r--core/java/android/accounts/AccountManager.java173
-rw-r--r--core/java/android/accounts/AccountMonitor.java120
-rw-r--r--core/java/android/accounts/OnAccountsUpdatedListener.java (renamed from core/java/android/accounts/AccountMonitorListener.java)6
-rw-r--r--core/java/android/content/AbstractSyncableContentProvider.java88
-rw-r--r--core/java/android/content/AbstractTableMerger.java31
-rw-r--r--core/java/android/content/ContentResolver.java3
-rw-r--r--core/java/android/content/ISyncAdapter.aidl3
-rw-r--r--core/java/android/content/SyncAdapter.java5
-rw-r--r--core/java/android/content/SyncManager.java131
-rw-r--r--core/java/android/content/SyncStateContentProviderHelper.java43
-rw-r--r--core/java/android/content/SyncStorageEngine.java90
-rw-r--r--core/java/android/content/SyncableContentProvider.java19
-rw-r--r--core/java/android/content/TempProviderSyncAdapter.java15
-rw-r--r--core/java/android/provider/Calendar.java10
-rw-r--r--core/java/android/provider/Contacts.java17
-rw-r--r--core/java/android/provider/SubscribedFeeds.java31
-rw-r--r--core/java/android/provider/Sync.java36
-rw-r--r--core/java/android/provider/SyncConstValue.java11
-rw-r--r--packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java47
-rw-r--r--packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsProvider.java15
-rw-r--r--preloaded-classes1
-rw-r--r--test-runner/android/test/SyncBaseInstrumentation.java14
-rw-r--r--tests/CoreTests/android/content/SyncStorageEngineTest.java3
-rw-r--r--tests/FrameworkTest/tests/src/android/content/AbstractTableMergerTest.java35
25 files changed, 631 insertions, 457 deletions
diff --git a/api/current.xml b/api/current.xml
index 9125da5..caffcaf 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -13092,6 +13092,23 @@
<parameter name="handler" type="android.os.Handler">
</parameter>
</method>
+<method name="addOnAccountsUpdatedListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.accounts.OnAccountsUpdatedListener">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+<parameter name="updateImmediately" type="boolean">
+</parameter>
+</method>
<method name="blockingAddAccountExplicitly"
return="boolean"
abstract="false"
@@ -13636,6 +13653,19 @@
<parameter name="handler" type="android.os.Handler">
</parameter>
</method>
+<method name="removeOnAccountsUpdatedListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.accounts.OnAccountsUpdatedListener">
+</parameter>
+</method>
<method name="setAuthToken"
return="android.accounts.Future1&lt;java.lang.Void&gt;"
abstract="false"
@@ -13721,74 +13751,6 @@
</parameter>
</method>
</class>
-<class name="AccountMonitor"
- extends="android.content.BroadcastReceiver"
- abstract="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<constructor name="AccountMonitor"
- type="android.accounts.AccountMonitor"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="context" type="android.content.Context">
-</parameter>
-<parameter name="listener" type="android.accounts.AccountMonitorListener">
-</parameter>
-</constructor>
-<method name="close"
- return="void"
- abstract="false"
- native="false"
- synchronized="true"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="onReceive"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="context" type="android.content.Context">
-</parameter>
-<parameter name="intent" type="android.content.Intent">
-</parameter>
-</method>
-</class>
-<interface name="AccountMonitorListener"
- abstract="true"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<method name="onAccountsUpdated"
- return="void"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="currentAccounts" type="java.lang.String[]">
-</parameter>
-</method>
-</interface>
<class name="AuthenticatorBindHelper"
extends="java.lang.Object"
abstract="false"
@@ -14704,6 +14666,27 @@
</parameter>
</constructor>
</class>
+<interface name="OnAccountsUpdatedListener"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onAccountsUpdated"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="accounts" type="android.accounts.Account[]">
+</parameter>
+</method>
+</interface>
<class name="OperationCanceledException"
extends="java.lang.Exception"
abstract="false"
@@ -99012,6 +98995,17 @@
visibility="public"
>
</field>
+<field name="GROUP_SYNC_ACCOUNT_TYPE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;group_sync_account_type&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="GROUP_SYNC_ID"
type="java.lang.String"
transient="false"
@@ -100954,6 +100948,17 @@
visibility="public"
>
</field>
+<field name="_SYNC_ACCOUNT_TYPE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;_sync_account_type&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
</interface>
<class name="LiveFolders"
extends="java.lang.Object"
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 007a490..3d21101 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -19,11 +19,15 @@ package android.accounts;
import android.app.Activity;
import android.content.Intent;
import android.content.Context;
+import android.content.IntentFilter;
+import android.content.BroadcastReceiver;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
import android.os.Parcelable;
+import android.util.Config;
+import android.util.Log;
import java.io.IOException;
import java.util.concurrent.Callable;
@@ -32,6 +36,10 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.TimeUnit;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.google.android.collect.Maps;
/**
* A class that helps with interactions with the AccountManagerService. It provides
@@ -48,6 +56,7 @@ public class AccountManager {
private final Context mContext;
private final IAccountManager mService;
+ private final Handler mMainHandler;
/**
* @hide
@@ -55,6 +64,7 @@ public class AccountManager {
public AccountManager(Context context, IAccountManager service) {
mContext = context;
mService = service;
+ mMainHandler = new Handler(mContext.getMainLooper());
}
public static AccountManager get(Context context) {
@@ -454,24 +464,28 @@ public class AccountManager {
private void postToHandler(Handler handler, final Future2Callback callback,
final Future2 future) {
- if (handler == null) {
- handler = new Handler(mContext.getMainLooper());
- }
- final Handler innerHandler = handler;
- innerHandler.post(new Runnable() {
+ handler = handler == null ? mMainHandler : handler;
+ handler.post(new Runnable() {
public void run() {
callback.run(future);
}
});
}
+ private void postToHandler(Handler handler, final OnAccountsUpdatedListener listener,
+ final Account[] accounts) {
+ handler = handler == null ? mMainHandler : handler;
+ handler.post(new Runnable() {
+ public void run() {
+ listener.onAccountsUpdated(accounts);
+ }
+ });
+ }
+
private <V> void postToHandler(Handler handler, final Future1Callback<V> callback,
final Future1<V> future) {
- if (handler == null) {
- handler = new Handler(mContext.getMainLooper());
- }
- final Handler innerHandler = handler;
- innerHandler.post(new Runnable() {
+ handler = handler == null ? mMainHandler : handler;
+ handler.post(new Runnable() {
public void run() {
callback.run(future);
}
@@ -908,4 +922,143 @@ public class AccountManager {
new GetAuthTokenByTypeAndFeaturesTask(accountType, authTokenType, features,
activityForPrompting, addAccountOptions, loginOptions, callback, handler).start();
}
+
+ private final HashMap<OnAccountsUpdatedListener, Handler> mAccountsUpdatedListeners =
+ Maps.newHashMap();
+
+ // These variable are only used from the LOGIN_ACCOUNTS_CHANGED_ACTION BroadcastReceiver
+ // and its getAccounts() callback which are both invoked only on the main thread. As a
+ // result we don't need to protect against concurrent accesses and any changes are guaranteed
+ // to be visible when used. Basically, these two variables are thread-confined.
+ private Future1<Account[]> mAccountsLookupFuture = null;
+ private boolean mAccountLookupPending = false;
+
+ /**
+ * BroadcastReceiver that listens for the LOGIN_ACCOUNTS_CHANGED_ACTION intent
+ * so that it can read the updated list of accounts and send them to the listener
+ * in mAccountsUpdatedListeners.
+ */
+ private final BroadcastReceiver mAccountsChangedBroadcastReceiver = new BroadcastReceiver() {
+ public void onReceive(final Context context, final Intent intent) {
+ if (mAccountsLookupFuture != null) {
+ // an accounts lookup is already in progress,
+ // don't bother starting another request
+ mAccountLookupPending = true;
+ return;
+ }
+ // initiate a read of the accounts
+ mAccountsLookupFuture = getAccounts(new Future1Callback<Account[]>() {
+ public void run(Future1<Account[]> future) {
+ // clear the future so that future receives will try the lookup again
+ mAccountsLookupFuture = null;
+
+ // get the accounts array
+ Account[] accounts;
+ try {
+ accounts = future.getResult();
+ } catch (OperationCanceledException e) {
+ // this should never happen, but if it does pretend we got another
+ // accounts changed broadcast
+ if (Config.LOGD) {
+ Log.d(TAG, "the accounts lookup for listener notifications was "
+ + "canceled, try again by simulating the receipt of "
+ + "a LOGIN_ACCOUNTS_CHANGED_ACTION broadcast");
+ }
+ onReceive(context, intent);
+ return;
+ }
+
+ // send the result to the listeners
+ synchronized (mAccountsUpdatedListeners) {
+ for (Map.Entry<OnAccountsUpdatedListener, Handler> entry :
+ mAccountsUpdatedListeners.entrySet()) {
+ Account[] accountsCopy = new Account[accounts.length];
+ // send the listeners a copy to make sure that one doesn't
+ // change what another sees
+ System.arraycopy(accounts, 0, accountsCopy, 0, accountsCopy.length);
+ postToHandler(entry.getValue(), entry.getKey(), accountsCopy);
+ }
+ }
+
+ // If mAccountLookupPending was set when the account lookup finished it
+ // means that we had previously ignored a LOGIN_ACCOUNTS_CHANGED_ACTION
+ // intent because a lookup was already in progress. Now that we are done
+ // with this lookup and notification pretend that another intent
+ // was received by calling onReceive() directly.
+ if (mAccountLookupPending) {
+ mAccountLookupPending = false;
+ onReceive(context, intent);
+ return;
+ }
+ }
+ }, mMainHandler);
+ }
+ };
+
+ /**
+ * Add a {@link OnAccountsUpdatedListener} to this instance of the {@link AccountManager}.
+ * The listener is guaranteed to be invoked on the thread of the Handler that is passed
+ * in or the main thread's Handler if handler is null.
+ * @param listener the listener to add
+ * @param handler the Handler whose thread will be used to invoke the listener. If null
+ * the AccountManager context's main thread will be used.
+ * @param updateImmediately if true then the listener will be invoked as a result of this
+ * call.
+ * @throws IllegalArgumentException if listener is null
+ * @throws IllegalStateException if listener was already added
+ */
+ public void addOnAccountsUpdatedListener(final OnAccountsUpdatedListener listener,
+ Handler handler, boolean updateImmediately) {
+ if (listener == null) {
+ throw new IllegalArgumentException("the listener is null");
+ }
+ synchronized (mAccountsUpdatedListeners) {
+ if (mAccountsUpdatedListeners.containsKey(listener)) {
+ throw new IllegalStateException("this listener is already added");
+ }
+ final boolean wasEmpty = mAccountsUpdatedListeners.isEmpty();
+
+ mAccountsUpdatedListeners.put(listener, handler);
+
+ if (wasEmpty) {
+ // Register a broadcast receiver to monitor account changes
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(Constants.LOGIN_ACCOUNTS_CHANGED_ACTION);
+ mContext.registerReceiver(mAccountsChangedBroadcastReceiver, intentFilter);
+ }
+ }
+
+ if (updateImmediately) {
+ getAccounts(new Future1Callback<Account[]>() {
+ public void run(Future1<Account[]> future) {
+ try {
+ listener.onAccountsUpdated(future.getResult());
+ } catch (OperationCanceledException e) {
+ // ignore
+ }
+ }
+ }, handler);
+ }
+ }
+
+ /**
+ * Remove an {@link OnAccountsUpdatedListener} that was previously registered with
+ * {@link #addOnAccountsUpdatedListener}.
+ * @param listener the listener to remove
+ * @throws IllegalArgumentException if listener is null
+ * @throws IllegalStateException if listener was not already added
+ */
+ public void removeOnAccountsUpdatedListener(OnAccountsUpdatedListener listener) {
+ if (listener == null) {
+ throw new IllegalArgumentException("the listener is null");
+ }
+ synchronized (mAccountsUpdatedListeners) {
+ if (mAccountsUpdatedListeners.remove(listener) == null) {
+ throw new IllegalStateException("this listener was not previously added");
+ }
+ if (mAccountsUpdatedListeners.isEmpty()) {
+ mContext.unregisterReceiver(mAccountsChangedBroadcastReceiver);
+ }
+ }
+ }
}
diff --git a/core/java/android/accounts/AccountMonitor.java b/core/java/android/accounts/AccountMonitor.java
deleted file mode 100644
index 38032c5..0000000
--- a/core/java/android/accounts/AccountMonitor.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2007 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 android.accounts;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.*;
-
-/**
- * A helper class that calls back on the provided
- * AccountMonitorListener with the set of current accounts both when
- * it gets created and whenever the set changes. It does this by
- * binding to the AccountsService and registering to receive the
- * intent broadcast when the set of accounts is changed. The
- * connection to the accounts service is only made when it needs to
- * fetch the current list of accounts (that is, when the
- * AccountMonitor is first created, and when the intent is received).
- */
-public class AccountMonitor extends BroadcastReceiver {
- private static final String TAG = "AccountMonitor";
-
- private final Context mContext;
- private final AccountMonitorListener mListener;
- private boolean mClosed = false;
-
- private volatile Looper mServiceLooper;
- private volatile NotifierHandler mServiceHandler;
-
- /**
- * Initializes the AccountMonitor and initiates a bind to the
- * AccountsService to get the initial account list. For 1.0,
- * the "list" is always a single account.
- *
- * @param context the context we are running in
- * @param listener the user to notify when the account set changes
- */
- public AccountMonitor(Context context, AccountMonitorListener listener) {
- if (listener == null) {
- throw new IllegalArgumentException("listener is null");
- }
-
- mContext = context;
- mListener = listener;
-
- // Register a broadcast receiver to monitor account changes
- IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(Constants.LOGIN_ACCOUNTS_CHANGED_ACTION);
- intentFilter.addAction(Intent.ACTION_DEVICE_STORAGE_OK); // To recover from disk-full.
- mContext.registerReceiver(this, intentFilter);
-
- HandlerThread thread = new HandlerThread("AccountMonitorHandlerThread");
- thread.start();
- mServiceLooper = thread.getLooper();
- mServiceHandler = new NotifierHandler(mServiceLooper);
-
- mServiceHandler.sendEmptyMessage(0);
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- notifyListener();
- }
-
- private Future1Callback<Account[]> mGetAccountsCallback = new Future1Callback<Account[]>() {
- public void run(Future1<Account[]> future) {
- try {
- Account[] accounts = future.getResult();
- String[] accountNames = new String[accounts.length];
- for (int i = 0; i < accounts.length; i++) {
- accountNames[i] = accounts[i].mName;
- }
- mListener.onAccountsUpdated(accountNames);
- } catch (OperationCanceledException e) {
- // the request was canceled
- }
- }
- };
-
- private synchronized void notifyListener() {
- AccountManager.get(mContext).getAccounts(mGetAccountsCallback, null /* handler */);
- }
-
- /**
- * Unregisters the account receiver. Consecutive calls to this
- * method are harmless, but also do nothing. Once this call is
- * made no more notifications will occur.
- */
- public synchronized void close() {
- if (!mClosed) {
- mContext.unregisterReceiver(this);
- mClosed = true;
- }
- }
-
- private final class NotifierHandler extends Handler {
- public NotifierHandler(Looper looper) {
- super(looper);
- }
-
- public void handleMessage(Message msg) {
- notifyListener();
- }
- }
-}
diff --git a/core/java/android/accounts/AccountMonitorListener.java b/core/java/android/accounts/OnAccountsUpdatedListener.java
index d0bd9a9..bd249d0 100644
--- a/core/java/android/accounts/AccountMonitorListener.java
+++ b/core/java/android/accounts/OnAccountsUpdatedListener.java
@@ -19,11 +19,11 @@ package android.accounts;
/**
* An interface that contains the callback used by the AccountMonitor
*/
-public interface AccountMonitorListener {
+public interface OnAccountsUpdatedListener {
/**
* This invoked when the AccountMonitor starts up and whenever the account
* set changes.
- * @param currentAccounts the current accounts
+ * @param accounts the current accounts
*/
- void onAccountsUpdated(String[] currentAccounts);
+ void onAccountsUpdated(Account[] accounts);
}
diff --git a/core/java/android/content/AbstractSyncableContentProvider.java b/core/java/android/content/AbstractSyncableContentProvider.java
index ce6501c..edef332 100644
--- a/core/java/android/content/AbstractSyncableContentProvider.java
+++ b/core/java/android/content/AbstractSyncableContentProvider.java
@@ -4,8 +4,9 @@ import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteDatabase;
import android.database.Cursor;
import android.net.Uri;
-import android.accounts.AccountMonitor;
-import android.accounts.AccountMonitorListener;
+import android.accounts.OnAccountsUpdatedListener;
+import android.accounts.Account;
+import android.accounts.AccountManager;
import android.provider.SyncConstValue;
import android.util.Config;
import android.util.Log;
@@ -14,10 +15,11 @@ import android.text.TextUtils;
import java.util.Collections;
import java.util.Map;
-import java.util.HashMap;
import java.util.Vector;
import java.util.ArrayList;
+import com.google.android.collect.Maps;
+
/**
* A specialization of the ContentProvider that centralizes functionality
* used by ContentProviders that are syncable. It also wraps calls to the ContentProvider
@@ -32,21 +34,22 @@ public abstract class AbstractSyncableContentProvider extends SyncableContentPro
private final String mDatabaseName;
private final int mDatabaseVersion;
private final Uri mContentUri;
- private AccountMonitor mAccountMonitor;
/** the account set in the last call to onSyncStart() */
- private String mSyncingAccount;
+ private Account mSyncingAccount;
private SyncStateContentProviderHelper mSyncState = null;
- private static final String[] sAccountProjection = new String[] {SyncConstValue._SYNC_ACCOUNT};
+ private static final String[] sAccountProjection =
+ new String[] {SyncConstValue._SYNC_ACCOUNT, SyncConstValue._SYNC_ACCOUNT_TYPE};
private boolean mIsTemporary;
private AbstractTableMerger mCurrentMerger = null;
private boolean mIsMergeCancelled = false;
- private static final String SYNC_ACCOUNT_WHERE_CLAUSE = SyncConstValue._SYNC_ACCOUNT + "=?";
+ private static final String SYNC_ACCOUNT_WHERE_CLAUSE =
+ SyncConstValue._SYNC_ACCOUNT + "=? AND " + SyncConstValue._SYNC_ACCOUNT_TYPE + "=?";
protected boolean isTemporary() {
return mIsTemporary;
@@ -147,21 +150,23 @@ public abstract class AbstractSyncableContentProvider extends SyncableContentPro
@Override
public boolean onCreate() {
if (isTemporary()) throw new IllegalStateException("onCreate() called for temp provider");
- mOpenHelper = new AbstractSyncableContentProvider.DatabaseHelper(getContext(), mDatabaseName);
+ mOpenHelper = new AbstractSyncableContentProvider.DatabaseHelper(getContext(),
+ mDatabaseName);
mSyncState = new SyncStateContentProviderHelper(mOpenHelper);
-
- AccountMonitorListener listener = new AccountMonitorListener() {
- public void onAccountsUpdated(String[] accounts) {
- // Some providers override onAccountsChanged(); give them a database to work with.
- mDb = mOpenHelper.getWritableDatabase();
- onAccountsChanged(accounts);
- TempProviderSyncAdapter syncAdapter = (TempProviderSyncAdapter)getSyncAdapter();
- if (syncAdapter != null) {
- syncAdapter.onAccountsChanged(accounts);
- }
- }
- };
- mAccountMonitor = new AccountMonitor(getContext(), listener);
+ AccountManager.get(getContext()).addOnAccountsUpdatedListener(
+ new OnAccountsUpdatedListener() {
+ public void onAccountsUpdated(Account[] accounts) {
+ // Some providers override onAccountsChanged(); give them a database to
+ // work with.
+ mDb = mOpenHelper.getWritableDatabase();
+ onAccountsChanged(accounts);
+ TempProviderSyncAdapter syncAdapter =
+ (TempProviderSyncAdapter)getSyncAdapter();
+ if (syncAdapter != null) {
+ syncAdapter.onAccountsChanged(accounts);
+ }
+ }
+ }, null /* handler */, true /* updateImmediately */);
return true;
}
@@ -365,8 +370,8 @@ public abstract class AbstractSyncableContentProvider extends SyncableContentPro
* @param context the sync context for the operation
* @param account
*/
- public void onSyncStart(SyncContext context, String account) {
- if (TextUtils.isEmpty(account)) {
+ public void onSyncStart(SyncContext context, Account account) {
+ if (account == null) {
throw new IllegalArgumentException("you passed in an empty account");
}
mSyncingAccount = account;
@@ -385,7 +390,7 @@ public abstract class AbstractSyncableContentProvider extends SyncableContentPro
* The account of the most recent call to onSyncStart()
* @return the account
*/
- public String getSyncingAccount() {
+ public Account getSyncingAccount() {
return mSyncingAccount;
}
@@ -496,12 +501,11 @@ public abstract class AbstractSyncableContentProvider extends SyncableContentPro
* Make sure that there are no entries for accounts that no longer exist
* @param accountsArray the array of currently-existing accounts
*/
- protected void onAccountsChanged(String[] accountsArray) {
- Map<String, Boolean> accounts = new HashMap<String, Boolean>();
- for (String account : accountsArray) {
+ protected void onAccountsChanged(Account[] accountsArray) {
+ Map<Account, Boolean> accounts = Maps.newHashMap();
+ for (Account account : accountsArray) {
accounts.put(account, false);
}
- accounts.put(SyncConstValue.NON_SYNCABLE_ACCOUNT, false);
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
Map<String, String> tableMap = db.getSyncedTables();
@@ -513,8 +517,7 @@ public abstract class AbstractSyncableContentProvider extends SyncableContentPro
try {
mSyncState.onAccountsChanged(accountsArray);
for (String table : tables) {
- deleteRowsForRemovedAccounts(accounts, table,
- SyncConstValue._SYNC_ACCOUNT);
+ deleteRowsForRemovedAccounts(accounts, table);
}
db.setTransactionSuccessful();
} finally {
@@ -529,23 +532,23 @@ public abstract class AbstractSyncableContentProvider extends SyncableContentPro
*
* @param accounts a map of existing accounts
* @param table the table to delete from
- * @param accountColumnName the name of the column that is expected
- * to hold the account.
*/
- protected void deleteRowsForRemovedAccounts(Map<String, Boolean> accounts,
- String table, String accountColumnName) {
+ protected void deleteRowsForRemovedAccounts(Map<Account, Boolean> accounts, String table) {
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
Cursor c = db.query(table, sAccountProjection, null, null,
- accountColumnName, null, null);
+ "_sync_account, _sync_account_type", null, null);
try {
while (c.moveToNext()) {
- String account = c.getString(0);
- if (TextUtils.isEmpty(account)) {
+ String accountName = c.getString(0);
+ String accountType = c.getString(1);
+ if (TextUtils.isEmpty(accountName)) {
continue;
}
+ Account account = new Account(accountName, accountType);
if (!accounts.containsKey(account)) {
int numDeleted;
- numDeleted = db.delete(table, accountColumnName + "=?", new String[]{account});
+ numDeleted = db.delete(table, "_sync_account=? AND _sync_account_type=?",
+ new String[]{account.mName, account.mType});
if (Config.LOGV) {
Log.v(TAG, "deleted " + numDeleted
+ " records from table " + table
@@ -562,7 +565,7 @@ public abstract class AbstractSyncableContentProvider extends SyncableContentPro
* Called when the sync system determines that this provider should no longer
* contain records for the specified account.
*/
- public void wipeAccount(String account) {
+ public void wipeAccount(Account account) {
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
Map<String, String> tableMap = db.getSyncedTables();
ArrayList<String> tables = new ArrayList<String>();
@@ -577,7 +580,8 @@ public abstract class AbstractSyncableContentProvider extends SyncableContentPro
// remove the data in the synced tables
for (String table : tables) {
- db.delete(table, SYNC_ACCOUNT_WHERE_CLAUSE, new String[]{account});
+ db.delete(table, SYNC_ACCOUNT_WHERE_CLAUSE,
+ new String[]{account.mName, account.mType});
}
db.setTransactionSuccessful();
} finally {
@@ -588,14 +592,14 @@ public abstract class AbstractSyncableContentProvider extends SyncableContentPro
/**
* Retrieves the SyncData bytes for the given account. The byte array returned may be null.
*/
- public byte[] readSyncDataBytes(String account) {
+ public byte[] readSyncDataBytes(Account account) {
return mSyncState.readSyncDataBytes(mOpenHelper.getReadableDatabase(), account);
}
/**
* Sets the SyncData bytes for the given account. The byte array may be null.
*/
- public void writeSyncDataBytes(String account, byte[] data) {
+ public void writeSyncDataBytes(Account account, byte[] data) {
mSyncState.writeSyncDataBytes(mOpenHelper.getWritableDatabase(), account, data);
}
}
diff --git a/core/java/android/content/AbstractTableMerger.java b/core/java/android/content/AbstractTableMerger.java
index 5588513..8c9955a 100644
--- a/core/java/android/content/AbstractTableMerger.java
+++ b/core/java/android/content/AbstractTableMerger.java
@@ -25,6 +25,7 @@ import android.provider.BaseColumns;
import static android.provider.SyncConstValue.*;
import android.text.TextUtils;
import android.util.Log;
+import android.accounts.Account;
/**
* @hide
@@ -55,14 +56,16 @@ public abstract class AbstractTableMerger
private volatile boolean mIsMergeCancelled;
- private static final String SELECT_MARKED = _SYNC_MARK + "> 0 and " + _SYNC_ACCOUNT + "=?";
+ private static final String SELECT_MARKED = _SYNC_MARK + "> 0 and "
+ + _SYNC_ACCOUNT + "=? and " + _SYNC_ACCOUNT_TYPE + "=?";
private static final String SELECT_BY_SYNC_ID_AND_ACCOUNT =
- _SYNC_ID +"=? and " + _SYNC_ACCOUNT + "=?";
+ _SYNC_ID +"=? and " + _SYNC_ACCOUNT + "=? and " + _SYNC_ACCOUNT_TYPE + "=?";
private static final String SELECT_BY_ID = BaseColumns._ID +"=?";
private static final String SELECT_UNSYNCED = ""
- + _SYNC_DIRTY + " > 0 and (" + _SYNC_ACCOUNT + "=? or " + _SYNC_ACCOUNT + " is null)";
+ + _SYNC_DIRTY + " > 0 and ((" + _SYNC_ACCOUNT + "=? AND " + _SYNC_ACCOUNT_TYPE + "=?) "
+ + "or " + _SYNC_ACCOUNT + " is null)";
public AbstractTableMerger(SQLiteDatabase database,
String table, Uri tableURL, String deletedTable,
@@ -132,7 +135,7 @@ public abstract class AbstractTableMerger
* construct a temporary instance to hold them.
*/
public void merge(final SyncContext context,
- final String account,
+ final Account account,
final SyncableContentProvider serverDiffs,
TempProviderSyncResult result,
SyncResult syncResult, SyncableContentProvider temporaryInstanceFactory) {
@@ -155,7 +158,7 @@ public abstract class AbstractTableMerger
* @hide this is public for testing purposes only
*/
public void mergeServerDiffs(SyncContext context,
- String account, SyncableContentProvider serverDiffs, SyncResult syncResult) {
+ Account account, SyncableContentProvider serverDiffs, SyncResult syncResult) {
boolean diffsArePartial = serverDiffs.getContainsDiffs();
// mark the current rows so that we can distinguish these from new
// inserts that occur during the merge
@@ -169,7 +172,7 @@ public abstract class AbstractTableMerger
Cursor diffsCursor = null;
try {
// load the local database entries, so we can merge them with the server
- final String[] accountSelectionArgs = new String[]{account};
+ final String[] accountSelectionArgs = new String[]{account.mName, account.mType};
localCursor = mDb.query(mTable, syncDirtyProjection,
SELECT_MARKED, accountSelectionArgs, null, null,
mTable + "." + _SYNC_ID);
@@ -462,7 +465,7 @@ public abstract class AbstractTableMerger
}
}
- private void fullyDeleteMatchingRows(Cursor diffsCursor, String account,
+ private void fullyDeleteMatchingRows(Cursor diffsCursor, Account account,
SyncResult syncResult) {
int serverSyncIdColumn = diffsCursor.getColumnIndexOrThrow(_SYNC_ID);
final boolean deleteBySyncId = !diffsCursor.isNull(serverSyncIdColumn);
@@ -472,7 +475,8 @@ public abstract class AbstractTableMerger
Cursor c = null;
try {
if (deleteBySyncId) {
- selectionArgs = new String[]{diffsCursor.getString(serverSyncIdColumn), account};
+ selectionArgs = new String[]{diffsCursor.getString(serverSyncIdColumn),
+ account.mName, account.mType};
c = mDb.query(mTable, new String[]{BaseColumns._ID}, SELECT_BY_SYNC_ID_AND_ACCOUNT,
selectionArgs, null, null, null);
} else {
@@ -505,21 +509,21 @@ public abstract class AbstractTableMerger
* Finds local changes, placing the results in the given result object.
* @param temporaryInstanceFactory As an optimization for the case
* where there are no client-side diffs, mergeResult may initially
- * have no {@link android.content.TempProviderSyncResult#tempContentProvider}. If this is
+ * have no {@link TempProviderSyncResult#tempContentProvider}. If this is
* the first in the sequence of AbstractTableMergers to find
* client-side diffs, it will use the given ContentProvider to
* create a temporary instance and store its {@link
- * ContentProvider} in the mergeResult.
+ * android.content.ContentProvider} in the mergeResult.
* @param account
* @param syncResult
*/
private void findLocalChanges(TempProviderSyncResult mergeResult,
- SyncableContentProvider temporaryInstanceFactory, String account,
+ SyncableContentProvider temporaryInstanceFactory, Account account,
SyncResult syncResult) {
SyncableContentProvider clientDiffs = mergeResult.tempContentProvider;
if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "generating client updates");
- final String[] accountSelectionArgs = new String[]{account};
+ final String[] accountSelectionArgs = new String[]{account.mName, account.mType};
// Generate the client updates and insertions
// Create a cursor for dirty records
@@ -553,7 +557,8 @@ public abstract class AbstractTableMerger
if (mDeletedTable != null) {
Cursor deletedCursor = mDb.query(mDeletedTable,
syncIdAndVersionProjection,
- _SYNC_ACCOUNT + "=? AND " + _SYNC_ID + " IS NOT NULL", accountSelectionArgs,
+ _SYNC_ACCOUNT + "=? AND " + _SYNC_ACCOUNT_TYPE + "=? AND "
+ + _SYNC_ID + " IS NOT NULL", accountSelectionArgs,
null, null, mDeletedTable + "." + _SYNC_ID);
try {
numDeletedEntries = deletedCursor.getCount();
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 0a71d57..6577236 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -28,6 +28,7 @@ import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.text.TextUtils;
+import android.accounts.Account;
import java.io.File;
import java.io.FileInputStream;
@@ -691,6 +692,7 @@ public abstract class ContentResolver {
* <li>Float</li>
* <li>Double</li>
* <li>String</li>
+ * <li>Account</li>
* <li>null</li>
* </ul>
* @param extras the Bundle to check
@@ -706,6 +708,7 @@ public abstract class ContentResolver {
if (value instanceof Float) continue;
if (value instanceof Double) continue;
if (value instanceof String) continue;
+ if (value instanceof Account) continue;
throw new IllegalArgumentException("unexpected value type: "
+ value.getClass().getName());
}
diff --git a/core/java/android/content/ISyncAdapter.aidl b/core/java/android/content/ISyncAdapter.aidl
index 671188c..d228605 100644
--- a/core/java/android/content/ISyncAdapter.aidl
+++ b/core/java/android/content/ISyncAdapter.aidl
@@ -16,6 +16,7 @@
package android.content;
+import android.accounts.Account;
import android.os.Bundle;
import android.content.ISyncContext;
@@ -33,7 +34,7 @@ oneway interface ISyncAdapter {
* @param account the account that should be synced
* @param extras SyncAdapter-specific parameters
*/
- void startSync(ISyncContext syncContext, String account, in Bundle extras);
+ void startSync(ISyncContext syncContext, in Account account, in Bundle extras);
/**
* Cancel the most recently initiated sync. Due to race conditions, this may arrive
diff --git a/core/java/android/content/SyncAdapter.java b/core/java/android/content/SyncAdapter.java
index 7826e50..3e91626 100644
--- a/core/java/android/content/SyncAdapter.java
+++ b/core/java/android/content/SyncAdapter.java
@@ -18,6 +18,7 @@ package android.content;
import android.os.Bundle;
import android.os.RemoteException;
+import android.accounts.Account;
/**
* @hide
@@ -29,7 +30,7 @@ public abstract class SyncAdapter {
public static final int LOG_SYNC_DETAILS = 2743;
class Transport extends ISyncAdapter.Stub {
- public void startSync(ISyncContext syncContext, String account,
+ public void startSync(ISyncContext syncContext, Account account,
Bundle extras) throws RemoteException {
SyncAdapter.this.startSync(new SyncContext(syncContext), account, extras);
}
@@ -59,7 +60,7 @@ public abstract class SyncAdapter {
* @param account the account that should be synced
* @param extras SyncAdapter-specific parameters
*/
- public abstract void startSync(SyncContext syncContext, String account, Bundle extras);
+ public abstract void startSync(SyncContext syncContext, Account account, Bundle extras);
/**
* Cancel the most recently initiated sync. Due to race conditions, this may arrive
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index 01b07eb..4474c62 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -21,8 +21,9 @@ import com.google.android.collect.Maps;
import com.android.internal.R;
import com.android.internal.util.ArrayUtils;
-import android.accounts.AccountMonitor;
-import android.accounts.AccountMonitorListener;
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.accounts.OnAccountsUpdatedListener;
import android.app.AlarmManager;
import android.app.Notification;
import android.app.NotificationManager;
@@ -50,8 +51,6 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
-import android.preference.Preference;
-import android.preference.PreferenceGroup;
import android.provider.Sync;
import android.provider.Settings;
import android.provider.Sync.History;
@@ -84,7 +83,7 @@ import java.util.Observable;
/**
* @hide
*/
-class SyncManager {
+class SyncManager implements OnAccountsUpdatedListener {
private static final String TAG = "SyncManager";
// used during dumping of the Sync history
@@ -130,9 +129,7 @@ class SyncManager {
private String mStatusText = "";
private long mHeartbeatTime = 0;
- private AccountMonitor mAccountMonitor;
-
- private volatile String[] mAccounts = null;
+ private volatile Account[] mAccounts = null;
volatile private PowerManager.WakeLock mSyncWakeLock;
volatile private PowerManager.WakeLock mHandleAlarmWakeLock;
@@ -184,43 +181,39 @@ class SyncManager {
private BroadcastReceiver mBootCompletedReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
if (!mFactoryTest) {
- AccountMonitorListener listener = new AccountMonitorListener() {
- public void onAccountsUpdated(String[] accounts) {
- final boolean hadAccountsAlready = mAccounts != null;
- // copy the accounts into a new array and change mAccounts to point to it
- String[] newAccounts = new String[accounts.length];
- System.arraycopy(accounts, 0, newAccounts, 0, accounts.length);
- mAccounts = newAccounts;
-
- // if a sync is in progress yet it is no longer in the accounts list,
- // cancel it
- ActiveSyncContext activeSyncContext = mActiveSyncContext;
- if (activeSyncContext != null) {
- if (!ArrayUtils.contains(newAccounts,
- activeSyncContext.mSyncOperation.account)) {
- Log.d(TAG, "canceling sync since the account has been removed");
- sendSyncFinishedOrCanceledMessage(activeSyncContext,
- null /* no result since this is a cancel */);
- }
- }
-
- // we must do this since we don't bother scheduling alarms when
- // the accounts are not set yet
- sendCheckAlarmsMessage();
+ AccountManager.get(mContext).addOnAccountsUpdatedListener(SyncManager.this,
+ mSyncHandler, true /* updateImmediately */);
+ }
+ }
+ };
- mSyncStorageEngine.doDatabaseCleanup(accounts);
+ public void onAccountsUpdated(Account[] accounts) {
+ final boolean hadAccountsAlready = mAccounts != null;
+ mAccounts = accounts;
- if (hadAccountsAlready && mAccounts.length > 0) {
- // request a sync so that if the password was changed we will
- // retry any sync that failed when it was wrong
- startSync(null /* all providers */, null /* no extras */);
- }
- }
- };
- mAccountMonitor = new AccountMonitor(context, listener);
+ // if a sync is in progress yet it is no longer in the accounts list,
+ // cancel it
+ ActiveSyncContext activeSyncContext = mActiveSyncContext;
+ if (activeSyncContext != null) {
+ if (!ArrayUtils.contains(accounts, activeSyncContext.mSyncOperation.account)) {
+ Log.d(TAG, "canceling sync since the account has been removed");
+ sendSyncFinishedOrCanceledMessage(activeSyncContext,
+ null /* no result since this is a cancel */);
}
}
- };
+
+ // we must do this since we don't bother scheduling alarms when
+ // the accounts are not set yet
+ sendCheckAlarmsMessage();
+
+ mSyncStorageEngine.doDatabaseCleanup(accounts);
+
+ if (hadAccountsAlready && accounts.length > 0) {
+ // request a sync so that if the password was changed we will
+ // retry any sync that failed when it was wrong
+ startSync(null /* all providers */, null /* no extras */);
+ }
+ }
private BroadcastReceiver mConnectivityIntentReceiver =
new BroadcastReceiver() {
@@ -486,7 +479,7 @@ class SyncManager {
}
}
- public String getSyncingAccount() {
+ public Account getSyncingAccount() {
ActiveSyncContext activeSyncContext = mActiveSyncContext;
return (activeSyncContext != null) ? activeSyncContext.mSyncOperation.account : null;
}
@@ -557,10 +550,10 @@ class SyncManager {
delay = -1; // this means schedule at the front of the queue
}
- String[] accounts;
- String accountFromExtras = extras.getString(ContentResolver.SYNC_EXTRAS_ACCOUNT);
- if (!TextUtils.isEmpty(accountFromExtras)) {
- accounts = new String[]{accountFromExtras};
+ Account[] accounts;
+ Account accountFromExtras = extras.getParcelable(ContentResolver.SYNC_EXTRAS_ACCOUNT);
+ if (accountFromExtras != null) {
+ accounts = new Account[]{accountFromExtras};
} else {
// if the accounts aren't configured yet then we can't support an account-less
// sync request
@@ -605,7 +598,7 @@ class SyncManager {
for (int i = 0; i < numProviders; i++) {
if (!providers.get(i).isSyncable) continue;
final String name = names.get(i);
- for (String account : accounts) {
+ for (Account account : accounts) {
scheduleSyncOperation(new SyncOperation(account, source, name, extras, delay));
// TODO: remove this when Calendar supports multiple accounts. Until then
// pretend that only the first account exists when syncing calendar.
@@ -881,7 +874,7 @@ class SyncManager {
* Value type that represents a sync operation.
*/
static class SyncOperation implements Comparable {
- final String account;
+ final Account account;
int syncSource;
String authority;
Bundle extras;
@@ -890,7 +883,7 @@ class SyncManager {
long delay;
Long rowId = null;
- SyncOperation(String account, int source, String authority, Bundle extras, long delay) {
+ SyncOperation(Account account, int source, String authority, Bundle extras, long delay) {
this.account = account;
this.syncSource = source;
this.authority = authority;
@@ -1024,7 +1017,7 @@ class SyncManager {
sb.append("data connected: ").append(mDataConnectionIsConnected).append("\n");
sb.append("memory low: ").append(mStorageIsLow).append("\n");
- final String[] accounts = mAccounts;
+ final Account[] accounts = mAccounts;
sb.append("accounts: ");
if (accounts != null) {
sb.append(accounts.length);
@@ -1095,17 +1088,18 @@ class SyncManager {
c.close();
}
- String currentAccount = null;
+ Account currentAccount = null;
c = mSyncStorageEngine.query(Sync.Status.CONTENT_URI,
- STATUS_PROJECTION, null, null, "account, authority");
+ STATUS_PROJECTION, null, null, "account_type, account, authority");
sb.append("\nSync history by account and authority\n");
try {
while (c.moveToNext()) {
- if (!TextUtils.equals(currentAccount, c.getString(0))) {
+ final Account account = new Account(c.getString(0), c.getString(13));
+ if (!account.equals(currentAccount)) {
if (currentAccount != null) {
dumpSyncHistoryFooter(sb);
}
- currentAccount = c.getString(0);
+ currentAccount = account;
dumpSyncHistoryHeader(sb, currentAccount);
}
@@ -1117,8 +1111,8 @@ class SyncManager {
}
}
- private void dumpSyncHistoryHeader(StringBuilder sb, String account) {
- sb.append(" Account: ").append(account).append("\n");
+ private void dumpSyncHistoryHeader(StringBuilder sb, Account account) {
+ sb.append(" ").append(account).append("\n");
sb.append(" ___________________________________________________________________________________________________________________________\n");
sb.append(" | | num times synced | total | last success | |\n");
sb.append(" | authority | local | poll | server | user | total | duration | source | time | result if failing |\n");
@@ -1137,7 +1131,8 @@ class SyncManager {
Sync.Status.LAST_SUCCESS_TIME, // 9
Sync.Status.LAST_FAILURE_SOURCE, // 10
Sync.Status.LAST_FAILURE_TIME, // 11
- Sync.Status.LAST_FAILURE_MESG // 12
+ Sync.Status.LAST_FAILURE_MESG, // 12
+ Sync.Status.ACCOUNT_TYPE, // 13
};
private void dumpSyncHistoryRow(StringBuilder sb, Cursor c) {
@@ -1305,7 +1300,7 @@ class SyncManager {
*/
class SyncNotificationInfo {
// only valid if isActive is true
- public String account;
+ public Account account;
// only valid if isActive is true
public String authority;
@@ -1460,7 +1455,7 @@ class SyncManager {
// If the accounts aren't known yet then we aren't ready to run. We will be kicked
// when the account lookup request does complete.
- String[] accounts = mAccounts;
+ Account[] accounts = mAccounts;
if (accounts == null) {
if (isLoggable) {
Log.v(TAG, "runStateIdle: accounts not known, skipping");
@@ -1857,7 +1852,7 @@ class SyncManager {
mContext.sendBroadcast(syncStateIntent);
}
- private void installHandleTooManyDeletesNotification(String account, String authority,
+ private void installHandleTooManyDeletesNotification(Account account, String authority,
long numDeletes) {
if (mNotificationMgr == null) return;
Intent clickIntent = new Intent();
@@ -1937,14 +1932,16 @@ class SyncManager {
"_id",
"authority",
"account",
+ "account_type",
"extras",
- "source"
+ "source",
};
private static final int COLUMN_ID = 0;
private static final int COLUMN_AUTHORITY = 1;
private static final int COLUMN_ACCOUNT = 2;
- private static final int COLUMN_EXTRAS = 3;
- private static final int COLUMN_SOURCE = 4;
+ private static final int COLUMN_ACCOUNT_TYPE = 3;
+ private static final int COLUMN_EXTRAS = 4;
+ private static final int COLUMN_SOURCE = 5;
private static final boolean DEBUG_CHECK_DATA_CONSISTENCY = false;
@@ -2026,7 +2023,8 @@ class SyncManager {
parcel.recycle();
}
ContentValues values = new ContentValues();
- values.put("account", operation.account);
+ values.put("account", operation.account.mName);
+ values.put("account_type", operation.account.mType);
values.put("authority", operation.authority);
values.put("source", operation.syncSource);
values.put("extras", extrasData);
@@ -2084,7 +2082,7 @@ class SyncManager {
if (DEBUG_CHECK_DATA_CONSISTENCY) debugCheckDataStructures(true /* check the DB */);
}
- public void clear(String account, String authority) {
+ public void clear(Account account, String authority) {
Iterator<Map.Entry<String, SyncOperation>> entries = mOpsByKey.entrySet().iterator();
while (entries.hasNext()) {
Map.Entry<String, SyncOperation> entry = entries.next();
@@ -2175,7 +2173,8 @@ class SyncManager {
}
SyncOperation syncOperation = new SyncOperation(
- cursor.getString(COLUMN_ACCOUNT),
+ new Account(cursor.getString(COLUMN_ACCOUNT),
+ cursor.getString(COLUMN_ACCOUNT_TYPE)),
cursor.getInt(COLUMN_SOURCE),
cursor.getString(COLUMN_AUTHORITY),
extras,
diff --git a/core/java/android/content/SyncStateContentProviderHelper.java b/core/java/android/content/SyncStateContentProviderHelper.java
index f503e6f..dc728ec 100644
--- a/core/java/android/content/SyncStateContentProviderHelper.java
+++ b/core/java/android/content/SyncStateContentProviderHelper.java
@@ -23,6 +23,7 @@ import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.net.Uri;
+import android.accounts.Account;
/**
* Extends the schema of a ContentProvider to include the _sync_state table
@@ -43,14 +44,15 @@ public class SyncStateContentProviderHelper {
private static final Uri CONTENT_URI =
Uri.parse("content://" + SYNC_STATE_AUTHORITY + "/state");
- private static final String ACCOUNT_WHERE = "_sync_account = ?";
+ private static final String ACCOUNT_WHERE = "_sync_account = ? AND _sync_account_type = ?";
private final Provider mInternalProviderInterface;
private static final String SYNC_STATE_TABLE = "_sync_state";
- private static long DB_VERSION = 2;
+ private static long DB_VERSION = 3;
- private static final String[] ACCOUNT_PROJECTION = new String[]{"_sync_account"};
+ private static final String[] ACCOUNT_PROJECTION =
+ new String[]{"_sync_account", "_sync_account_type"};
static {
sURIMatcher.addURI(SYNC_STATE_AUTHORITY, "state", STATE);
@@ -70,8 +72,9 @@ public class SyncStateContentProviderHelper {
db.execSQL("CREATE TABLE _sync_state (" +
"_id INTEGER PRIMARY KEY," +
"_sync_account TEXT," +
+ "_sync_account_type TEXT," +
"data TEXT," +
- "UNIQUE(_sync_account)" +
+ "UNIQUE(_sync_account, _sync_account_type)" +
");");
db.execSQL("DROP TABLE IF EXISTS _sync_state_metadata");
@@ -168,15 +171,17 @@ public class SyncStateContentProviderHelper {
* @param account the account of the row that should be copied over.
*/
public void copySyncState(SQLiteDatabase dbSrc, SQLiteDatabase dbDest,
- String account) {
- final String[] whereArgs = new String[]{account};
- Cursor c = dbSrc.query(SYNC_STATE_TABLE, new String[]{"_sync_account", "data"},
+ Account account) {
+ final String[] whereArgs = new String[]{account.mName, account.mType};
+ Cursor c = dbSrc.query(SYNC_STATE_TABLE,
+ new String[]{"_sync_account", "_sync_account_type", "data"},
ACCOUNT_WHERE, whereArgs, null, null, null);
try {
if (c.moveToNext()) {
ContentValues values = new ContentValues();
values.put("_sync_account", c.getString(0));
- values.put("data", c.getBlob(1));
+ values.put("_sync_account_type", c.getString(1));
+ values.put("data", c.getBlob(2));
dbDest.replace(SYNC_STATE_TABLE, "_sync_account", values);
}
} finally {
@@ -184,14 +189,17 @@ public class SyncStateContentProviderHelper {
}
}
- public void onAccountsChanged(String[] accounts) {
+ public void onAccountsChanged(Account[] accounts) {
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
Cursor c = db.query(SYNC_STATE_TABLE, ACCOUNT_PROJECTION, null, null, null, null, null);
try {
while (c.moveToNext()) {
- final String account = c.getString(0);
+ final String accountName = c.getString(0);
+ final String accountType = c.getString(1);
+ Account account = new Account(accountName, accountType);
if (!ArrayUtils.contains(accounts, account)) {
- db.delete(SYNC_STATE_TABLE, ACCOUNT_WHERE, new String[]{account});
+ db.delete(SYNC_STATE_TABLE, ACCOUNT_WHERE,
+ new String[]{accountName, accountType});
}
}
} finally {
@@ -199,9 +207,9 @@ public class SyncStateContentProviderHelper {
}
}
- public void discardSyncData(SQLiteDatabase db, String account) {
+ public void discardSyncData(SQLiteDatabase db, Account account) {
if (account != null) {
- db.delete(SYNC_STATE_TABLE, ACCOUNT_WHERE, new String[]{account});
+ db.delete(SYNC_STATE_TABLE, ACCOUNT_WHERE, new String[]{account.mName, account.mType});
} else {
db.delete(SYNC_STATE_TABLE, null, null);
}
@@ -210,9 +218,9 @@ public class SyncStateContentProviderHelper {
/**
* Retrieves the SyncData bytes for the given account. The byte array returned may be null.
*/
- public byte[] readSyncDataBytes(SQLiteDatabase db, String account) {
+ public byte[] readSyncDataBytes(SQLiteDatabase db, Account account) {
Cursor c = db.query(SYNC_STATE_TABLE, null, ACCOUNT_WHERE,
- new String[]{account}, null, null, null);
+ new String[]{account.mName, account.mType}, null, null, null);
try {
if (c.moveToFirst()) {
return c.getBlob(c.getColumnIndexOrThrow("data"));
@@ -226,9 +234,10 @@ public class SyncStateContentProviderHelper {
/**
* Sets the SyncData bytes for the given account. The bytes array may be null.
*/
- public void writeSyncDataBytes(SQLiteDatabase db, String account, byte[] data) {
+ public void writeSyncDataBytes(SQLiteDatabase db, Account account, byte[] data) {
ContentValues values = new ContentValues();
values.put("data", data);
- db.update(SYNC_STATE_TABLE, values, ACCOUNT_WHERE, new String[]{account});
+ db.update(SYNC_STATE_TABLE, values, ACCOUNT_WHERE,
+ new String[]{account.mName, account.mType});
}
}
diff --git a/core/java/android/content/SyncStorageEngine.java b/core/java/android/content/SyncStorageEngine.java
index 282f6e7..2ad44d2 100644
--- a/core/java/android/content/SyncStorageEngine.java
+++ b/core/java/android/content/SyncStorageEngine.java
@@ -1,6 +1,7 @@
package android.content;
import android.Manifest;
+import android.accounts.Account;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteDatabase;
@@ -16,6 +17,8 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
+import com.google.android.collect.Sets;
+
/**
* ContentProvider that tracks the sync data and overall sync
* history on the device.
@@ -26,7 +29,7 @@ public class SyncStorageEngine {
private static final String TAG = "SyncManager";
private static final String DATABASE_NAME = "syncmanager.db";
- private static final int DATABASE_VERSION = 10;
+ private static final int DATABASE_VERSION = 11;
private static final int STATS = 1;
private static final int STATS_ID = 2;
@@ -63,17 +66,20 @@ public class SyncStorageEngine {
PENDING_PROJECTION_MAP = map = new HashMap<String,String>();
map.put(Sync.History._ID, Sync.History._ID);
map.put(Sync.History.ACCOUNT, Sync.History.ACCOUNT);
+ map.put(Sync.History.ACCOUNT_TYPE, Sync.History.ACCOUNT_TYPE);
map.put(Sync.History.AUTHORITY, Sync.History.AUTHORITY);
ACTIVE_PROJECTION_MAP = map = new HashMap<String,String>();
map.put(Sync.History._ID, Sync.History._ID);
map.put(Sync.History.ACCOUNT, Sync.History.ACCOUNT);
+ map.put(Sync.History.ACCOUNT_TYPE, Sync.History.ACCOUNT_TYPE);
map.put(Sync.History.AUTHORITY, Sync.History.AUTHORITY);
map.put("startTime", "startTime");
HISTORY_PROJECTION_MAP = map = new HashMap<String,String>();
map.put(Sync.History._ID, "history._id as _id");
map.put(Sync.History.ACCOUNT, "stats.account as account");
+ map.put(Sync.History.ACCOUNT_TYPE, "stats.account_type as account_type");
map.put(Sync.History.AUTHORITY, "stats.authority as authority");
map.put(Sync.History.EVENT, Sync.History.EVENT);
map.put(Sync.History.EVENT_TIME, Sync.History.EVENT_TIME);
@@ -86,6 +92,7 @@ public class SyncStorageEngine {
STATUS_PROJECTION_MAP = map = new HashMap<String,String>();
map.put(Sync.Status._ID, "status._id as _id");
map.put(Sync.Status.ACCOUNT, "stats.account as account");
+ map.put(Sync.Status.ACCOUNT_TYPE, "stats.account_type as account_type");
map.put(Sync.Status.AUTHORITY, "stats.authority as authority");
map.put(Sync.Status.TOTAL_ELAPSED_TIME, Sync.Status.TOTAL_ELAPSED_TIME);
map.put(Sync.Status.NUM_SYNCS, Sync.Status.NUM_SYNCS);
@@ -102,7 +109,7 @@ public class SyncStorageEngine {
}
private static final String[] STATS_ACCOUNT_PROJECTION =
- new String[] { Sync.Stats.ACCOUNT };
+ new String[] { Sync.Stats.ACCOUNT, Sync.Stats.ACCOUNT_TYPE };
private static final int MAX_HISTORY_EVENTS_TO_KEEP = 5000;
@@ -151,6 +158,7 @@ public class SyncStorageEngine {
+ "_id INTEGER PRIMARY KEY,"
+ "authority TEXT NOT NULL,"
+ "account TEXT NOT NULL,"
+ + "account_type TEXT NOT NULL,"
+ "extras BLOB NOT NULL,"
+ "source INTEGER NOT NULL"
+ ");");
@@ -158,6 +166,7 @@ public class SyncStorageEngine {
db.execSQL("CREATE TABLE stats (" +
"_id INTEGER PRIMARY KEY," +
"account TEXT, " +
+ "account_type TEXT, " +
"authority TEXT, " +
"syncdata TEXT, " +
"UNIQUE (account, authority)" +
@@ -195,6 +204,7 @@ public class SyncStorageEngine {
+ "_id INTEGER PRIMARY KEY,"
+ "authority TEXT,"
+ "account TEXT,"
+ + "account_type TEXT,"
+ "startTime INTEGER);");
db.execSQL("CREATE INDEX historyEventTime ON history (eventTime)");
@@ -206,10 +216,27 @@ public class SyncStorageEngine {
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- if (oldVersion == 9 && newVersion == 10) {
+ if (oldVersion == 9) {
Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
+ newVersion + ", which will preserve old data");
db.execSQL("ALTER TABLE status ADD COLUMN initialFailureTime INTEGER");
+ oldVersion++;
+ }
+
+ if (oldVersion == 10) {
+ Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
+ + newVersion + ", which will preserve old data");
+ db.execSQL("ALTER TABLE pending ADD COLUMN account_type TEXT");
+ db.execSQL("ALTER TABLE stats ADD COLUMN account_type TEXT");
+ db.execSQL("ALTER TABLE active ADD COLUMN account_type TEXT");
+
+ db.execSQL("UPDATE pending SET account_type='com.google.GAIA'");
+ db.execSQL("UPDATE stats SET account_type='com.google.GAIA'");
+ db.execSQL("UPDATE active SET account_type='com.google.GAIA'");
+ oldVersion++;
+ }
+
+ if (oldVersion == newVersion) {
return;
}
@@ -233,23 +260,23 @@ public class SyncStorageEngine {
}
}
- protected void doDatabaseCleanup(String[] accounts) {
- HashSet<String> currentAccounts = new HashSet<String>();
- for (String account : accounts) currentAccounts.add(account);
+ protected void doDatabaseCleanup(Account[] accounts) {
+ HashSet<Account> currentAccounts = Sets.newHashSet(accounts);
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
Cursor cursor = db.query("stats", STATS_ACCOUNT_PROJECTION,
- null /* where */, null /* where args */, Sync.Stats.ACCOUNT,
+ null /* where */, null /* where args */,
+ Sync.Stats.ACCOUNT + "," + Sync.Stats.ACCOUNT_TYPE,
null /* having */, null /* order by */);
try {
while (cursor.moveToNext()) {
- String account = cursor.getString(0);
- if (TextUtils.isEmpty(account)) {
- continue;
- }
+ String accountName = cursor.getString(0);
+ String accountType = cursor.getString(1);
+ final Account account = new Account(accountName, accountType);
if (!currentAccounts.contains(account)) {
- String where = Sync.Stats.ACCOUNT + "=?";
+ String where = Sync.Stats.ACCOUNT + "=? AND " + Sync.Stats.ACCOUNT_TYPE + "=?";
int numDeleted;
- numDeleted = db.delete("stats", where, new String[]{account});
+ numDeleted = db.delete("stats", where,
+ new String[]{account.mName, account.mType});
if (Config.LOGD) {
Log.d(TAG, "deleted " + numDeleted
+ " records from stats table"
@@ -272,10 +299,11 @@ public class SyncStorageEngine {
}
}
- private int updateActiveSync(String account, String authority, Long startTime) {
+ private int updateActiveSync(Account account, String authority, Long startTime) {
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
ContentValues values = new ContentValues();
- values.put("account", account);
+ values.put("account", account == null ? null : account.mName);
+ values.put("account_type", account == null ? null : account.mType);
values.put("authority", authority);
values.put("startTime", startTime);
int numChanges = db.update("active", values, null, null);
@@ -463,7 +491,9 @@ public class SyncStorageEngine {
db.beginTransaction();
long rowId = db.insert("pending", Sync.Pending.ACCOUNT, values);
if (rowId < 0) return null;
- String account = values.getAsString(Sync.Pending.ACCOUNT);
+ String accountName = values.getAsString(Sync.Pending.ACCOUNT);
+ String accountType = values.getAsString(Sync.Pending.ACCOUNT_TYPE);
+ final Account account = new Account(accountName, accountType);
String authority = values.getAsString(Sync.Pending.AUTHORITY);
long statsId = createStatsRowIfNecessary(account, authority);
@@ -491,25 +521,31 @@ public class SyncStorageEngine {
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
db.beginTransaction();
try {
- String account;
+ Account account;
String authority;
Cursor c = db.query("pending",
- new String[]{Sync.Pending.ACCOUNT, Sync.Pending.AUTHORITY},
+ new String[]{Sync.Pending.ACCOUNT, Sync.Pending.ACCOUNT_TYPE,
+ Sync.Pending.AUTHORITY},
"_id=" + rowId, null, null, null, null);
try {
if (c.getCount() != 1) {
return 0;
}
c.moveToNext();
- account = c.getString(0);
- authority = c.getString(1);
+ String accountName = c.getString(0);
+ String accountType = c.getString(1);
+ account = new Account(accountName, accountType);
+ authority = c.getString(2);
} finally {
c.close();
}
db.delete("pending", "_id=" + rowId, null /* no where args */);
- final String[] accountAuthorityWhereArgs = new String[]{account, authority};
+ final String[] accountAuthorityWhereArgs =
+ new String[]{account.mName, account.mType, authority};
boolean isPending = 0 < DatabaseUtils.longForQuery(db,
- "SELECT COUNT(*) FROM PENDING WHERE account=? AND authority=?",
+ "SELECT COUNT(*)"
+ + " FROM PENDING"
+ + " WHERE account=? AND account_type=? AND authority=?",
accountAuthorityWhereArgs);
if (!isPending) {
long statsId = createStatsRowIfNecessary(account, authority);
@@ -581,7 +617,7 @@ public class SyncStorageEngine {
return numDeletes > 0;
}
- public long insertStartSyncEvent(String account, String authority, long now, int source) {
+ public long insertStartSyncEvent(Account account, String authority, long now, int source) {
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
long statsId = createStatsRowIfNecessary(account, authority);
@@ -731,14 +767,15 @@ public class SyncStorageEngine {
}
}
- private long createStatsRowIfNecessary(String account, String authority) {
+ private long createStatsRowIfNecessary(Account account, String authority) {
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
StringBuilder where = new StringBuilder();
where.append(Sync.Stats.ACCOUNT + "= ?");
+ where.append(" and " + Sync.Stats.ACCOUNT_TYPE + "= ?");
where.append(" and " + Sync.Stats.AUTHORITY + "= ?");
Cursor cursor = query(Sync.Stats.CONTENT_URI,
Sync.Stats.SYNC_STATS_PROJECTION,
- where.toString(), new String[] { account, authority },
+ where.toString(), new String[] { account.mName, account.mType, authority },
null /* order */);
try {
long id;
@@ -746,7 +783,8 @@ public class SyncStorageEngine {
id = cursor.getLong(cursor.getColumnIndexOrThrow(Sync.Stats._ID));
} else {
ContentValues values = new ContentValues();
- values.put(Sync.Stats.ACCOUNT, account);
+ values.put(Sync.Stats.ACCOUNT, account.mName);
+ values.put(Sync.Stats.ACCOUNT_TYPE, account.mType);
values.put(Sync.Stats.AUTHORITY, authority);
id = db.insert("stats", null, values);
}
diff --git a/core/java/android/content/SyncableContentProvider.java b/core/java/android/content/SyncableContentProvider.java
index e0cd786..93ebbea 100644
--- a/core/java/android/content/SyncableContentProvider.java
+++ b/core/java/android/content/SyncableContentProvider.java
@@ -19,6 +19,7 @@ package android.content;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
+import android.accounts.Account;
import java.util.Map;
@@ -110,7 +111,7 @@ public abstract class SyncableContentProvider extends ContentProvider {
* @param context the sync context for the operation
* @param account
*/
- public abstract void onSyncStart(SyncContext context, String account);
+ public abstract void onSyncStart(SyncContext context, Account account);
/**
* Called right after a sync is completed
@@ -124,7 +125,7 @@ public abstract class SyncableContentProvider extends ContentProvider {
* The account of the most recent call to onSyncStart()
* @return the account
*/
- public abstract String getSyncingAccount();
+ public abstract Account getSyncingAccount();
/**
* Merge diffs from a sync source with this content provider.
@@ -194,7 +195,7 @@ public abstract class SyncableContentProvider extends ContentProvider {
* Make sure that there are no entries for accounts that no longer exist
* @param accountsArray the array of currently-existing accounts
*/
- protected abstract void onAccountsChanged(String[] accountsArray);
+ protected abstract void onAccountsChanged(Account[] accountsArray);
/**
* A helper method to delete all rows whose account is not in the accounts
@@ -203,26 +204,24 @@ public abstract class SyncableContentProvider extends ContentProvider {
*
* @param accounts a map of existing accounts
* @param table the table to delete from
- * @param accountColumnName the name of the column that is expected
- * to hold the account.
*/
- protected abstract void deleteRowsForRemovedAccounts(Map<String, Boolean> accounts,
- String table, String accountColumnName);
+ protected abstract void deleteRowsForRemovedAccounts(Map<Account, Boolean> accounts,
+ String table);
/**
* Called when the sync system determines that this provider should no longer
* contain records for the specified account.
*/
- public abstract void wipeAccount(String account);
+ public abstract void wipeAccount(Account account);
/**
* Retrieves the SyncData bytes for the given account. The byte array returned may be null.
*/
- public abstract byte[] readSyncDataBytes(String account);
+ public abstract byte[] readSyncDataBytes(Account account);
/**
* Sets the SyncData bytes for the given account. The bytes array may be null.
*/
- public abstract void writeSyncDataBytes(String account, byte[] data);
+ public abstract void writeSyncDataBytes(Account account, byte[] data);
}
diff --git a/core/java/android/content/TempProviderSyncAdapter.java b/core/java/android/content/TempProviderSyncAdapter.java
index eb3a5da..0cbe01e 100644
--- a/core/java/android/content/TempProviderSyncAdapter.java
+++ b/core/java/android/content/TempProviderSyncAdapter.java
@@ -12,6 +12,7 @@ import android.util.Config;
import android.util.EventLog;
import android.util.Log;
import android.util.TimingLogger;
+import android.accounts.Account;
/**
* @hide
@@ -67,7 +68,7 @@ public abstract class TempProviderSyncAdapter extends SyncAdapter {
* @return true, if the sync was successfully started. One reason it can
* fail to start is if there is no user configured on the device.
*/
- public abstract void onSyncStarting(SyncContext context, String account, boolean forced,
+ public abstract void onSyncStarting(SyncContext context, Account account, boolean forced,
SyncResult result);
/**
@@ -168,12 +169,12 @@ public abstract class TempProviderSyncAdapter extends SyncAdapter {
* exist.
* @param accounts the list of accounts
*/
- public abstract void onAccountsChanged(String[] accounts);
+ public abstract void onAccountsChanged(Account[] accounts);
private Context mContext;
private class SyncThread extends Thread {
- private final String mAccount;
+ private final Account mAccount;
private final Bundle mExtras;
private final SyncContext mSyncContext;
private volatile boolean mIsCanceled = false;
@@ -181,7 +182,7 @@ public abstract class TempProviderSyncAdapter extends SyncAdapter {
private long mInitialRxBytes;
private final SyncResult mResult;
- SyncThread(SyncContext syncContext, String account, Bundle extras) {
+ SyncThread(SyncContext syncContext, Account account, Bundle extras) {
super("SyncThread");
mAccount = account;
mExtras = extras;
@@ -221,7 +222,7 @@ public abstract class TempProviderSyncAdapter extends SyncAdapter {
}
}
- private void sync(SyncContext syncContext, String account, Bundle extras) {
+ private void sync(SyncContext syncContext, Account account, Bundle extras) {
mIsCanceled = false;
mProviderSyncStarted = false;
@@ -273,7 +274,7 @@ public abstract class TempProviderSyncAdapter extends SyncAdapter {
}
}
- private void runSyncLoop(SyncContext syncContext, String account, Bundle extras) {
+ private void runSyncLoop(SyncContext syncContext, Account account, Bundle extras) {
TimingLogger syncTimer = new TimingLogger(TAG + "Profiling", "sync");
syncTimer.addSplit("start");
int loopCount = 0;
@@ -518,7 +519,7 @@ public abstract class TempProviderSyncAdapter extends SyncAdapter {
EventLog.writeEvent(SyncAdapter.LOG_SYNC_DETAILS, TAG, bytesSent, bytesReceived, "");
}
- public void startSync(SyncContext syncContext, String account, Bundle extras) {
+ public void startSync(SyncContext syncContext, Account account, Bundle extras) {
if (mSyncThread != null) {
syncContext.onFinished(SyncResult.ALREADY_IN_PROGRESS);
return;
diff --git a/core/java/android/provider/Calendar.java b/core/java/android/provider/Calendar.java
index 4a709f6..3a221e4 100644
--- a/core/java/android/provider/Calendar.java
+++ b/core/java/android/provider/Calendar.java
@@ -32,6 +32,7 @@ import android.text.format.DateUtils;
import android.text.format.Time;
import android.util.Config;
import android.util.Log;
+import android.accounts.Account;
import com.android.internal.database.ArrayListCursor;
import com.google.android.gdata.client.AndroidGDataClient;
import com.google.android.gdata.client.AndroidXmlParserFactory;
@@ -157,11 +158,12 @@ public final class Calendar {
* @param account the account whose rows should be deleted
* @return the count of rows that were deleted
*/
- public static int deleteCalendarsForAccount(ContentResolver cr,
- String account) {
+ public static int deleteCalendarsForAccount(ContentResolver cr, Account account) {
// delete all calendars that match this account
- return Calendar.Calendars.delete(cr, Calendar.Calendars._SYNC_ACCOUNT + "=?",
- new String[] {account});
+ return Calendar.Calendars.delete(cr,
+ Calendar.Calendars._SYNC_ACCOUNT + "=? AND "
+ + Calendar.Calendars._SYNC_ACCOUNT_TYPE + "=?",
+ new String[] {account.mName, account.mType});
}
/**
diff --git a/core/java/android/provider/Contacts.java b/core/java/android/provider/Contacts.java
index 064ed88..a6450f3 100644
--- a/core/java/android/provider/Contacts.java
+++ b/core/java/android/provider/Contacts.java
@@ -30,6 +30,7 @@ import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;
import android.widget.ImageView;
+import android.accounts.Account;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
@@ -75,6 +76,12 @@ public class Contacts {
public static final String _SYNC_ACCOUNT = "_sync_account";
/**
+ * The _SYNC_ACCOUNT_TYPE to which this setting corresponds. This may be null.
+ * <P>Type: TEXT</P>
+ */
+ public static final String _SYNC_ACCOUNT_TYPE = "_sync_account_type";
+
+ /**
* The key of this setting.
* <P>Type: TEXT</P>
*/
@@ -134,6 +141,7 @@ public class Contacts {
selectString = (account == null)
? "_sync_account is null AND key=?"
: "_sync_account=? AND key=?";
+// : "_sync_account=? AND _sync_account_type=? AND key=?";
selectArgs = (account == null)
? new String[]{key}
: new String[]{account, key};
@@ -158,7 +166,8 @@ public class Contacts {
// the account name is, so we're using a global setting for SYNC_EVERYTHING.
// Some day when we add multiple accounts to the UI this should honor the account
// that was asked for.
- //values.put(_SYNC_ACCOUNT, account);
+ //values.put(_SYNC_ACCOUNT, account.mName);
+ //values.put(_SYNC_ACCOUNT_TYPE, account.mType);
values.put(KEY, key);
values.put(VALUE, value);
cr.update(Settings.CONTENT_URI, values, null, null);
@@ -840,6 +849,12 @@ public class Contacts {
public static final String GROUP_SYNC_ACCOUNT = "group_sync_account";
/**
+ * The account type of the group.
+ * <P>Type: TEXT</P>
+ */
+ public static final String GROUP_SYNC_ACCOUNT_TYPE = "group_sync_account_type";
+
+ /**
* The row id of the person.
* <P>Type: TEXT</P>
*/
diff --git a/core/java/android/provider/SubscribedFeeds.java b/core/java/android/provider/SubscribedFeeds.java
index 4d430d5..f94b442 100644
--- a/core/java/android/provider/SubscribedFeeds.java
+++ b/core/java/android/provider/SubscribedFeeds.java
@@ -20,6 +20,7 @@ import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
+import android.accounts.Account;
/**
* The SubscribedFeeds provider stores all information about subscribed feeds.
@@ -99,7 +100,7 @@ public class SubscribedFeeds {
/**
* The default sort order for this table
*/
- public static final String DEFAULT_SORT_ORDER = "_SYNC_ACCOUNT ASC";
+ public static final String DEFAULT_SORT_ORDER = "_SYNC_ACCOUNT_TYPE, _SYNC_ACCOUNT ASC";
}
/**
@@ -114,38 +115,36 @@ public class SubscribedFeeds {
* @return the Uri of the feed that was added
*/
public static Uri addFeed(ContentResolver resolver,
- String feed, String account,
+ String feed, Account account,
String authority, String service) {
ContentValues values = new ContentValues();
values.put(SubscribedFeeds.Feeds.FEED, feed);
- values.put(SubscribedFeeds.Feeds._SYNC_ACCOUNT, account);
+ values.put(SubscribedFeeds.Feeds._SYNC_ACCOUNT, account.mName);
+ values.put(SubscribedFeeds.Feeds._SYNC_ACCOUNT_TYPE, account.mType);
values.put(SubscribedFeeds.Feeds.AUTHORITY, authority);
values.put(SubscribedFeeds.Feeds.SERVICE, service);
return resolver.insert(SubscribedFeeds.Feeds.CONTENT_URI, values);
}
public static int deleteFeed(ContentResolver resolver,
- String feed, String account, String authority) {
+ String feed, Account account, String authority) {
StringBuilder where = new StringBuilder();
where.append(SubscribedFeeds.Feeds._SYNC_ACCOUNT + "=?");
+ where.append(" AND " + SubscribedFeeds.Feeds._SYNC_ACCOUNT_TYPE + "=?");
where.append(" AND " + SubscribedFeeds.Feeds.FEED + "=?");
where.append(" AND " + SubscribedFeeds.Feeds.AUTHORITY + "=?");
return resolver.delete(SubscribedFeeds.Feeds.CONTENT_URI,
- where.toString(), new String[] {account, feed, authority});
+ where.toString(), new String[] {account.mName, account.mType, feed, authority});
}
public static int deleteFeeds(ContentResolver resolver,
- String account, String authority) {
+ Account account, String authority) {
StringBuilder where = new StringBuilder();
where.append(SubscribedFeeds.Feeds._SYNC_ACCOUNT + "=?");
+ where.append(" AND " + SubscribedFeeds.Feeds._SYNC_ACCOUNT_TYPE + "=?");
where.append(" AND " + SubscribedFeeds.Feeds.AUTHORITY + "=?");
return resolver.delete(SubscribedFeeds.Feeds.CONTENT_URI,
- where.toString(), new String[] {account, authority});
- }
-
- public static String gtalkServiceRoutingInfoFromAccountAndResource(
- String account, String res) {
- return Uri.parse("gtalk://" + account + "/" + res).toString();
+ where.toString(), new String[] {account.mName, account.mType, authority});
}
/**
@@ -157,6 +156,12 @@ public class SubscribedFeeds {
* <P>Type: TEXT</P>
*/
public static final String _SYNC_ACCOUNT = SyncConstValue._SYNC_ACCOUNT;
+
+ /**
+ * The account type.
+ * <P>Type: TEXT</P>
+ */
+ public static final String _SYNC_ACCOUNT_TYPE = SyncConstValue._SYNC_ACCOUNT_TYPE;
}
/**
@@ -199,6 +204,6 @@ public class SubscribedFeeds {
/**
* The default sort order for this table
*/
- public static final String DEFAULT_SORT_ORDER = "_SYNC_ACCOUNT ASC";
+ public static final String DEFAULT_SORT_ORDER = "_SYNC_ACCOUNT_TYPE, _SYNC_ACCOUNT ASC";
}
}
diff --git a/core/java/android/provider/Sync.java b/core/java/android/provider/Sync.java
index 628852f..c9bde0e 100644
--- a/core/java/android/provider/Sync.java
+++ b/core/java/android/provider/Sync.java
@@ -22,6 +22,8 @@ import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.Handler;
+import android.accounts.Account;
+import android.text.TextUtils;
import java.util.Map;
@@ -51,6 +53,12 @@ public final class Sync {
public static final String ACCOUNT = "account";
/**
+ * The sync account type.
+ * <P>Type: TEXT</P>
+ */
+ public static final String ACCOUNT_TYPE = "account_type";
+
+ /**
* The content authority (contacts, calendar, etc.).
* <P>Type: TEXT</P>
*/
@@ -280,7 +288,8 @@ public final class Sync {
public static final String MESG_CANCELED = "canceled";
private static final String FINISHED_SINCE_WHERE_CLAUSE = EVENT + "=" + EVENT_STOP
- + " AND " + EVENT_TIME + ">? AND " + ACCOUNT + "=? AND " + AUTHORITY + "=?";
+ + " AND " + EVENT_TIME + ">? AND " + ACCOUNT + "=? AND " + ACCOUNT_TYPE + "=?"
+ + " AND " + AUTHORITY + "=?";
public static String mesgToString(String mesg) {
if (MESG_SUCCESS.equals(mesg)) return mesg;
@@ -311,10 +320,11 @@ public final class Sync {
}
public static boolean hasNewerSyncFinished(ContentResolver contentResolver,
- String account, String authority, long when) {
+ Account account, String authority, long when) {
Cursor c = contentResolver.query(CONTENT_URI, new String[]{_ID},
FINISHED_SINCE_WHERE_CLAUSE,
- new String[]{Long.toString(when), account, authority}, null);
+ new String[]{Long.toString(when), account.mName, account.mType, authority},
+ null);
try {
return c.getCount() > 0;
} finally {
@@ -345,7 +355,8 @@ public final class Sync {
* @return the cursor on the AuthorityHistory table
*/
public static Cursor query(ContentResolver contentResolver) {
- return contentResolver.query(CONTENT_URI, null, null, null, ACCOUNT + ", " + AUTHORITY);
+ return contentResolver.query(CONTENT_URI, null, null, null,
+ ACCOUNT_TYPE + "," + ACCOUNT + "," + AUTHORITY);
}
public static class QueryMap extends ContentQueryMap {
@@ -356,10 +367,11 @@ public final class Sync {
_ID, keepUpdated, handlerForUpdateNotifications);
}
- public ContentValues get(String account, String authority) {
+ public ContentValues get(Account account, String authority) {
Map<String, ContentValues> rows = getRows();
for (ContentValues values : rows.values()) {
- if (values.getAsString(ACCOUNT).equals(account)
+ if (values.getAsString(ACCOUNT).equals(account.mName)
+ && values.getAsString(ACCOUNT_TYPE).equals(account.mType)
&& values.getAsString(AUTHORITY).equals(authority)) {
return values;
}
@@ -390,10 +402,11 @@ public final class Sync {
handlerForUpdateNotifications);
}
- public boolean isPending(String account, String authority) {
+ public boolean isPending(Account account, String authority) {
Map<String, ContentValues> rows = getRows();
for (ContentValues values : rows.values()) {
- if (values.getAsString(ACCOUNT).equals(account)
+ if (values.getAsString(ACCOUNT).equals(account.mName)
+ && values.getAsString(ACCOUNT_TYPE).equals(account.mType)
&& values.getAsString(AUTHORITY).equals(authority)) {
return true;
}
@@ -444,9 +457,12 @@ public final class Sync {
return null;
}
- public String getSyncingAccount() {
+ public Account getSyncingAccount() {
ContentValues values = getActiveSyncInfo();
- return (values == null) ? null : values.getAsString(ACCOUNT);
+ if (values == null || TextUtils.isEmpty(values.getAsString(ACCOUNT))) {
+ return null;
+ }
+ return new Account(values.getAsString(ACCOUNT), values.getAsString(ACCOUNT_TYPE));
}
public String getSyncingAuthority() {
diff --git a/core/java/android/provider/SyncConstValue.java b/core/java/android/provider/SyncConstValue.java
index 6eb4398..30966eb 100644
--- a/core/java/android/provider/SyncConstValue.java
+++ b/core/java/android/provider/SyncConstValue.java
@@ -29,6 +29,12 @@ public interface SyncConstValue
public static final String _SYNC_ACCOUNT = "_sync_account";
/**
+ * The type of the account that was used to sync the entry to the device.
+ * <P>Type: TEXT</P>
+ */
+ public static final String _SYNC_ACCOUNT_TYPE = "_sync_account_type";
+
+ /**
* The unique ID for a row assigned by the sync source. NULL if the row has never been synced.
* <P>Type: TEXT</P>
*/
@@ -68,4 +74,9 @@ public interface SyncConstValue
* Used to indicate that this account is not synced
*/
public static final String NON_SYNCABLE_ACCOUNT = "non_syncable";
+
+ /**
+ * Used to indicate that this account is not synced
+ */
+ public static final String NON_SYNCABLE_ACCOUNT_TYPE = "android.local";
}
diff --git a/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java b/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java
index 8268fee..de7b1d7 100644
--- a/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java
+++ b/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java
@@ -17,13 +17,15 @@ import android.database.sqlite.SQLiteFullException;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.os.Bundle;
-import android.os.Debug;
import android.text.TextUtils;
import android.net.Uri;
+import android.accounts.Account;
import java.util.ArrayList;
import java.util.Calendar;
+import com.google.android.collect.Lists;
+
/**
* A service to handle various intents asynchronously.
*/
@@ -31,7 +33,8 @@ public class SubscribedFeedsIntentService extends IntentService {
private static final String TAG = "Sync";
private static final String[] sAccountProjection =
- new String[] {SubscribedFeeds.Accounts._SYNC_ACCOUNT};
+ new String[] {SubscribedFeeds.Accounts._SYNC_ACCOUNT,
+ SubscribedFeeds.Accounts._SYNC_ACCOUNT_TYPE};
/** How often to refresh the subscriptions, in milliseconds */
private static final long SUBSCRIPTION_REFRESH_INTERVAL = 1000L * 60 * 60 * 24; // one day
@@ -56,10 +59,10 @@ public class SubscribedFeedsIntentService extends IntentService {
if (GTALK_DATA_MESSAGE_RECEIVED.equals(intent.getAction())) {
boolean fromTrustedServer = intent.getBooleanExtra("from_trusted_server", false);
if (fromTrustedServer) {
- String account = intent.getStringExtra("account");
+ String accountName = intent.getStringExtra("account");
String token = intent.getStringExtra("message_token");
- if (TextUtils.isEmpty(account) || TextUtils.isEmpty(token)) {
+ if (TextUtils.isEmpty(accountName) || TextUtils.isEmpty(token)) {
if (Config.LOGD) {
Log.d(TAG, "Ignoring malformed tickle -- missing account or token.");
}
@@ -68,10 +71,10 @@ public class SubscribedFeedsIntentService extends IntentService {
if (Config.LOGD) {
Log.d(TAG, "Received network tickle for "
- + account + " - " + token);
+ + accountName + " - " + token);
}
- handleTickle(this, account, token);
+ handleTickle(this, accountName, token);
} else {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Ignoring tickle -- not from trusted server.");
@@ -103,20 +106,22 @@ public class SubscribedFeedsIntentService extends IntentService {
alarmManager.set(AlarmManager.RTC, when, pendingIntent);
}
- private void handleTickle(Context context, String account, String feed) {
+ private void handleTickle(Context context, String accountName, String feed) {
Cursor c = null;
Sync.Settings.QueryMap syncSettings =
new Sync.Settings.QueryMap(context.getContentResolver(),
false /* don't keep updated */,
null /* not needed since keep updated is false */);
final String where = SubscribedFeeds.Feeds._SYNC_ACCOUNT + "= ? "
+ + "and " + SubscribedFeeds.Feeds._SYNC_ACCOUNT_TYPE + "= ? "
+ "and " + SubscribedFeeds.Feeds.FEED + "= ?";
try {
+ // TODO(fredq) fix the hardcoded type
c = context.getContentResolver().query(SubscribedFeeds.Feeds.CONTENT_URI,
- null, where, new String[]{account, feed}, null);
+ null, where, new String[]{accountName, "com.google.GAIA", feed}, null);
if (c.getCount() == 0) {
Log.w(TAG, "received tickle for non-existent feed: "
- + "account " + account + ", feed " + feed);
+ + "account " + accountName + ", feed " + feed);
EventLog.writeEvent(LOG_TICKLE, "unknown");
}
while (c.moveToNext()) {
@@ -131,7 +136,8 @@ public class SubscribedFeedsIntentService extends IntentService {
}
Uri uri = Uri.parse("content://" + authority);
Bundle extras = new Bundle();
- extras.putString(ContentResolver.SYNC_EXTRAS_ACCOUNT, account);
+ extras.putParcelable(ContentResolver.SYNC_EXTRAS_ACCOUNT,
+ new Account(accountName, "com.google.GAIA"));
extras.putString("feed", feed);
context.getContentResolver().startSync(uri, extras);
}
@@ -151,17 +157,15 @@ public class SubscribedFeedsIntentService extends IntentService {
*/
private void handleRefreshAlarm(Context context) {
// retrieve the list of accounts from the subscribed feeds
- ArrayList<String> accounts = new ArrayList<String>();
+ ArrayList<Account> accounts = Lists.newArrayList();
ContentResolver contentResolver = context.getContentResolver();
Cursor c = contentResolver.query(SubscribedFeeds.Accounts.CONTENT_URI,
sAccountProjection, null, null, null);
try {
while (c.moveToNext()) {
- String account = c.getString(0);
- if (TextUtils.isEmpty(account)) {
- continue;
- }
- accounts.add(account);
+ String accountName = c.getString(0);
+ String accountType = c.getString(1);
+ accounts.add(new Account(accountName, accountType));
}
} finally {
c.close();
@@ -169,16 +173,19 @@ public class SubscribedFeedsIntentService extends IntentService {
// Clear the auth tokens for all these accounts so that we are sure
// they will still be valid until the next time we refresh them.
- // TODO: add this when the google login service is done
+ // TODO(fredq): add this when the google login service is done
// mark the feeds dirty, by setting the accounts to the same value,
// which will trigger a sync.
try {
ContentValues values = new ContentValues();
- for (String account : accounts) {
- values.put(SyncConstValue._SYNC_ACCOUNT, account);
+ for (Account account : accounts) {
+ values.put(SyncConstValue._SYNC_ACCOUNT, account.mName);
+ values.put(SyncConstValue._SYNC_ACCOUNT_TYPE, account.mType);
contentResolver.update(SubscribedFeeds.Feeds.CONTENT_URI, values,
- SubscribedFeeds.Feeds._SYNC_ACCOUNT + "=?", new String[] {account});
+ SubscribedFeeds.Feeds._SYNC_ACCOUNT + "=? AND "
+ + SubscribedFeeds.Feeds._SYNC_ACCOUNT_TYPE + "=?",
+ new String[] {account.mName, account.mType});
}
} catch (SQLiteFullException e) {
Log.w(TAG, "disk full while trying to mark the feeds as dirty, skipping");
diff --git a/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsProvider.java b/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsProvider.java
index 9ecc3d6..d87f5e7 100644
--- a/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsProvider.java
+++ b/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsProvider.java
@@ -39,7 +39,7 @@ import java.util.HashMap;
public class SubscribedFeedsProvider extends AbstractSyncableContentProvider {
private static final String TAG = "SubscribedFeedsProvider";
private static final String DATABASE_NAME = "subscribedfeeds.db";
- private static final int DATABASE_VERSION = 10;
+ private static final int DATABASE_VERSION = 11;
private static final int FEEDS = 1;
private static final int FEED_ID = 2;
@@ -88,6 +88,7 @@ public class SubscribedFeedsProvider extends AbstractSyncableContentProvider {
db.execSQL("CREATE TABLE feeds (" +
"_id INTEGER PRIMARY KEY," +
"_sync_account TEXT," + // From the sync source
+ "_sync_account_type TEXT," + // From the sync source
"_sync_id TEXT," + // From the sync source
"_sync_time TEXT," + // From the sync source
"_sync_version TEXT," + // From the sync source
@@ -106,8 +107,8 @@ public class SubscribedFeedsProvider extends AbstractSyncableContentProvider {
"WHEN old._sync_id is not null " +
"BEGIN " +
"INSERT INTO _deleted_feeds " +
- "(_sync_id, _sync_account, _sync_version) " +
- "VALUES (old._sync_id, old._sync_account, " +
+ "(_sync_id, _sync_account, _sync_account_type, _sync_version) " +
+ "VALUES (old._sync_id, old._sync_account, old._sync_account_type, " +
"old._sync_version);" +
"END");
@@ -116,6 +117,7 @@ public class SubscribedFeedsProvider extends AbstractSyncableContentProvider {
"_sync_id TEXT," +
(isTemporary() ? "_sync_local_id INTEGER," : "") + // Used while syncing,
"_sync_account TEXT," +
+ "_sync_account_type TEXT," +
"_sync_mark INTEGER, " + // Used to filter out new rows
"UNIQUE(_sync_id))");
}
@@ -170,7 +172,8 @@ public class SubscribedFeedsProvider extends AbstractSyncableContentProvider {
qb.setDistinct(true);
qb.setProjectionMap(ACCOUNTS_PROJECTION_MAP);
return qb.query(getDatabase(), projection, selection, selectionArgs,
- SubscribedFeeds.Feeds._SYNC_ACCOUNT, null, sortOrder);
+ SubscribedFeeds.Feeds._SYNC_ACCOUNT_TYPE + ","
+ + SubscribedFeeds.Feeds._SYNC_ACCOUNT, null, sortOrder);
case FEED_ID:
qb.setTables(sFeedsTable);
qb.appendWhere(sFeedsTable + "._id=");
@@ -310,6 +313,8 @@ public class SubscribedFeedsProvider extends AbstractSyncableContentProvider {
DatabaseUtils.cursorStringToContentValues(diffsCursor,
SubscribedFeeds.Feeds._SYNC_ACCOUNT, mValues);
DatabaseUtils.cursorStringToContentValues(diffsCursor,
+ SubscribedFeeds.Feeds._SYNC_ACCOUNT_TYPE, mValues);
+ DatabaseUtils.cursorStringToContentValues(diffsCursor,
SubscribedFeeds.Feeds._SYNC_VERSION, mValues);
db.replace(mDeletedTable, SubscribedFeeds.Feeds._SYNC_ID, mValues);
}
@@ -369,5 +374,7 @@ public class SubscribedFeedsProvider extends AbstractSyncableContentProvider {
ACCOUNTS_PROJECTION_MAP = map;
map.put(SubscribedFeeds.Accounts._COUNT, "COUNT(*) AS _count");
map.put(SubscribedFeeds.Accounts._SYNC_ACCOUNT, SubscribedFeeds.Accounts._SYNC_ACCOUNT);
+ map.put(SubscribedFeeds.Accounts._SYNC_ACCOUNT_TYPE,
+ SubscribedFeeds.Accounts._SYNC_ACCOUNT_TYPE);
}
}
diff --git a/preloaded-classes b/preloaded-classes
index fc29906..d1360eb 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -1,6 +1,5 @@
# Classes which are preloaded by com.android.internal.os.ZygoteInit.
android.R$styleable
-android.accounts.AccountMonitor
android.app.Activity
android.app.ActivityGroup
android.app.ActivityManager$MemoryInfo$1
diff --git a/test-runner/android/test/SyncBaseInstrumentation.java b/test-runner/android/test/SyncBaseInstrumentation.java
index c1d2507..0b4bfed 100644
--- a/test-runner/android/test/SyncBaseInstrumentation.java
+++ b/test-runner/android/test/SyncBaseInstrumentation.java
@@ -23,6 +23,8 @@ import android.os.Bundle;
import android.os.SystemClock;
import android.provider.Sync;
import android.net.Uri;
+import android.accounts.Account;
+
import java.util.Map;
/**
@@ -49,7 +51,8 @@ public class SyncBaseInstrumentation extends InstrumentationTestCase {
protected void syncProvider(Uri uri, String account, String authority) throws Exception {
Bundle extras = new Bundle();
extras.putBoolean(ContentResolver.SYNC_EXTRAS_FORCE, true);
- extras.putString(ContentResolver.SYNC_EXTRAS_ACCOUNT, account);
+ Account account1 = new Account(account, "com.google.GAIA");
+ extras.putParcelable(ContentResolver.SYNC_EXTRAS_ACCOUNT, account1);
mContentResolver.startSync(uri, extras);
long startTimeInMillis = SystemClock.elapsedRealtime();
@@ -66,7 +69,7 @@ public class SyncBaseInstrumentation extends InstrumentationTestCase {
break;
}
- if (isSyncActive(account, authority)) {
+ if (isSyncActive(account1, authority)) {
counter = 0;
continue;
}
@@ -87,7 +90,7 @@ public class SyncBaseInstrumentation extends InstrumentationTestCase {
* entry is in either the Pending or Active tables.
* @return
*/
- private boolean isSyncActive(String account, String authority) {
+ private boolean isSyncActive(Account account, String authority) {
Sync.Pending.QueryMap pendingQueryMap = null;
Sync.Active.QueryMap activeQueryMap = null;
try {
@@ -107,11 +110,12 @@ public class SyncBaseInstrumentation extends InstrumentationTestCase {
}
}
- private boolean isActiveInActiveQueryMap(Sync.Active.QueryMap activemap, String account,
+ private boolean isActiveInActiveQueryMap(Sync.Active.QueryMap activemap, Account account,
String authority) {
Map<String, ContentValues> rows = activemap.getRows();
for (ContentValues values : rows.values()) {
- if (values.getAsString("account").equals(account)
+ if (values.getAsString("account").equals(account.mName)
+ && values.getAsString("account_type").equals(account.mType)
&& values.getAsString("authority").equals(authority)) {
return true;
}
diff --git a/tests/CoreTests/android/content/SyncStorageEngineTest.java b/tests/CoreTests/android/content/SyncStorageEngineTest.java
index 36805b1..27f1b8b 100644
--- a/tests/CoreTests/android/content/SyncStorageEngineTest.java
+++ b/tests/CoreTests/android/content/SyncStorageEngineTest.java
@@ -21,6 +21,7 @@ import android.test.RenamingDelegatingContext;
import android.test.mock.MockContext;
import android.test.mock.MockContentResolver;
import android.provider.Sync;
+import android.accounts.Account;
public class SyncStorageEngineTest extends AndroidTestCase {
@@ -29,7 +30,7 @@ public class SyncStorageEngineTest extends AndroidTestCase {
* correcponding sync is finished. This can happen if the clock changes while we are syncing.
*/
public void testPurgeActiveSync() throws Exception {
- final String account = "a@example.com";
+ final Account account = new Account("a@example.com", "example.type");
final String authority = "testprovider";
MockContentResolver mockResolver = new MockContentResolver();
diff --git a/tests/FrameworkTest/tests/src/android/content/AbstractTableMergerTest.java b/tests/FrameworkTest/tests/src/android/content/AbstractTableMergerTest.java
index aa3d186..42c1e78 100644
--- a/tests/FrameworkTest/tests/src/android/content/AbstractTableMergerTest.java
+++ b/tests/FrameworkTest/tests/src/android/content/AbstractTableMergerTest.java
@@ -8,6 +8,7 @@ import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.test.AndroidTestCase;
import android.text.TextUtils;
+import android.accounts.Account;
import java.util.ArrayList;
import java.util.Map;
@@ -26,7 +27,7 @@ public class AbstractTableMergerTest extends AndroidTestCase {
static final Uri TABLE_URI = Uri.withAppendedPath(CONTENT_URI, TABLE_NAME);
static final Uri DELETED_TABLE_URI = Uri.withAppendedPath(CONTENT_URI, DELETED_TABLE_NAME);
- private final String ACCOUNT = "account@goo.com";
+ private final Account ACCOUNT = new Account("account@goo.com", "example.type");
private final ArrayList<Expectation> mExpectations = Lists.newArrayList();
@@ -65,25 +66,31 @@ public class AbstractTableMergerTest extends AndroidTestCase {
mExpectations.clear();
}
- ContentValues newValues(String data, String syncId, String syncAccount,
+ ContentValues newValues(String data, String syncId, Account syncAccount,
String syncTime, String syncVersion, Long syncLocalId) {
ContentValues values = new ContentValues();
if (data != null) values.put("data", data);
if (syncTime != null) values.put("_sync_time", syncTime);
if (syncVersion != null) values.put("_sync_version", syncVersion);
if (syncId != null) values.put("_sync_id", syncId);
- if (syncAccount != null) values.put("_sync_account", syncAccount);
+ if (syncAccount != null) {
+ values.put("_sync_account", syncAccount.mName);
+ values.put("_sync_account_type", syncAccount.mType);
+ }
values.put("_sync_local_id", syncLocalId);
values.put("_sync_dirty", 0);
return values;
}
- ContentValues newDeletedValues(String syncId, String syncAccount, String syncVersion,
+ ContentValues newDeletedValues(String syncId, Account syncAccount, String syncVersion,
Long syncLocalId) {
ContentValues values = new ContentValues();
if (syncVersion != null) values.put("_sync_version", syncVersion);
if (syncId != null) values.put("_sync_id", syncId);
- if (syncAccount != null) values.put("_sync_account", syncAccount);
+ if (syncAccount != null) {
+ values.put("_sync_account", syncAccount.mName);
+ values.put("_sync_account_type", syncAccount.mType);
+ }
if (syncLocalId != null) values.put("_sync_local_id", syncLocalId);
return values;
}
@@ -380,6 +387,7 @@ public class AbstractTableMergerTest extends AndroidTestCase {
+ "_sync_local_id INTEGER, "
+ "_sync_dirty INTEGER NOT NULL DEFAULT 0, "
+ "_sync_account TEXT, "
+ + "_sync_account_type TEXT, "
+ "_sync_mark INTEGER)");
mDb.execSQL("CREATE TABLE deleted_items ("
@@ -388,6 +396,7 @@ public class AbstractTableMergerTest extends AndroidTestCase {
+ "_sync_id TEXT, "
+ "_sync_local_id INTEGER, "
+ "_sync_account TEXT, "
+ + "_sync_account_type TEXT, "
+ "_sync_mark INTEGER)");
}
@@ -501,7 +510,7 @@ public class AbstractTableMergerTest extends AndroidTestCase {
throw new UnsupportedOperationException();
}
- public void onSyncStart(SyncContext context, String account) {
+ public void onSyncStart(SyncContext context, Account account) {
throw new UnsupportedOperationException();
}
@@ -509,7 +518,7 @@ public class AbstractTableMergerTest extends AndroidTestCase {
throw new UnsupportedOperationException();
}
- public String getSyncingAccount() {
+ public Account getSyncingAccount() {
throw new UnsupportedOperationException();
}
@@ -544,24 +553,24 @@ public class AbstractTableMergerTest extends AndroidTestCase {
throw new UnsupportedOperationException();
}
- protected void onAccountsChanged(String[] accountsArray) {
+ protected void onAccountsChanged(Account[] accountsArray) {
throw new UnsupportedOperationException();
}
- protected void deleteRowsForRemovedAccounts(Map<String, Boolean> accounts, String table,
- String accountColumnName) {
+ protected void deleteRowsForRemovedAccounts(Map<Account, Boolean> accounts, String table
+ ) {
throw new UnsupportedOperationException();
}
- public void wipeAccount(String account) {
+ public void wipeAccount(Account account) {
throw new UnsupportedOperationException();
}
- public byte[] readSyncDataBytes(String account) {
+ public byte[] readSyncDataBytes(Account account) {
throw new UnsupportedOperationException();
}
- public void writeSyncDataBytes(String account, byte[] data) {
+ public void writeSyncDataBytes(Account account, byte[] data) {
throw new UnsupportedOperationException();
}
}