16c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng/* 26c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng * Copyright (C) 2009 The Android Open Source Project 36c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng * 46c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng * Licensed under the Apache License, Version 2.0 (the "License"); 56c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng * you may not use this file except in compliance with the License. 66c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng * You may obtain a copy of the License at 76c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng * 86c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng * http://www.apache.org/licenses/LICENSE-2.0 96c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng * 106c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng * Unless required by applicable law or agreed to in writing, software 116c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng * distributed under the License is distributed on an "AS IS" BASIS, 126c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng * See the License for the specific language governing permissions and 146c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng * limitations under the License. 156c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng */ 166c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng 1769c182afb0e6d82a341a28b4317aa703af768906Gary Maipackage com.android.contacts.model; 186c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng 196c712f45c80cef426a86fa14668a935c488d0ee4Chiao Chengimport android.accounts.Account; 20413589f0b9279e06d8913761cdcf03c8fef7ffd8Ihab Awadimport android.accounts.AccountManager; 216c712f45c80cef426a86fa14668a935c488d0ee4Chiao Chengimport android.accounts.OnAccountsUpdateListener; 226c712f45c80cef426a86fa14668a935c488d0ee4Chiao Chengimport android.content.BroadcastReceiver; 236c712f45c80cef426a86fa14668a935c488d0ee4Chiao Chengimport android.content.ContentResolver; 246c712f45c80cef426a86fa14668a935c488d0ee4Chiao Chengimport android.content.Context; 256c712f45c80cef426a86fa14668a935c488d0ee4Chiao Chengimport android.content.Intent; 266c712f45c80cef426a86fa14668a935c488d0ee4Chiao Chengimport android.content.IntentFilter; 2756c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wangimport android.content.SharedPreferences; 286c712f45c80cef426a86fa14668a935c488d0ee4Chiao Chengimport android.content.SyncStatusObserver; 296c712f45c80cef426a86fa14668a935c488d0ee4Chiao Chengimport android.content.pm.PackageManager; 30fac695a36b227f5591eac064ded8e8dad3398400Marcus Hagerottimport android.database.ContentObserver; 316c712f45c80cef426a86fa14668a935c488d0ee4Chiao Chengimport android.net.Uri; 326c712f45c80cef426a86fa14668a935c488d0ee4Chiao Chengimport android.os.Handler; 336c712f45c80cef426a86fa14668a935c488d0ee4Chiao Chengimport android.os.Looper; 346c712f45c80cef426a86fa14668a935c488d0ee4Chiao Chengimport android.provider.ContactsContract; 35fac695a36b227f5591eac064ded8e8dad3398400Marcus Hagerottimport android.support.v4.content.ContextCompat; 36e7a71cbbe8929a9d8a7ca0a3b5668646d49a611aMarcus Hagerottimport android.support.v4.content.LocalBroadcastManager; 376c712f45c80cef426a86fa14668a935c488d0ee4Chiao Chengimport android.text.TextUtils; 386c712f45c80cef426a86fa14668a935c488d0ee4Chiao Chengimport android.util.Log; 396c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng 400a49afa2ad697307cc04ef4cb86570574fa720f2Gary Maiimport com.android.contacts.Experiments; 4156c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wangimport com.android.contacts.R; 4269c182afb0e6d82a341a28b4317aa703af768906Gary Maiimport com.android.contacts.list.ContactListFilterController; 4375895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerottimport com.android.contacts.model.account.AccountInfo; 4469c182afb0e6d82a341a28b4317aa703af768906Gary Maiimport com.android.contacts.model.account.AccountType; 4504be88c2bec8d0a0cc9e1f4f0af3b3a2ff8ac4e7Marcus Hagerottimport com.android.contacts.model.account.AccountTypeProvider; 4669c182afb0e6d82a341a28b4317aa703af768906Gary Maiimport com.android.contacts.model.account.AccountTypeWithDataSet; 4769c182afb0e6d82a341a28b4317aa703af768906Gary Maiimport com.android.contacts.model.account.AccountWithDataSet; 4869c182afb0e6d82a341a28b4317aa703af768906Gary Maiimport com.android.contacts.model.account.FallbackAccountType; 4969c182afb0e6d82a341a28b4317aa703af768906Gary Maiimport com.android.contacts.model.account.GoogleAccountType; 5069c182afb0e6d82a341a28b4317aa703af768906Gary Maiimport com.android.contacts.model.dataitem.DataKind; 5104be88c2bec8d0a0cc9e1f4f0af3b3a2ff8ac4e7Marcus Hagerottimport com.android.contacts.util.concurrent.ContactsExecutors; 52511504f977e83a60049bc051ee7e6064ca2b0264Marcus Hagerottimport com.android.contactsbind.experiments.Flags; 5375895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerottimport com.google.common.base.Preconditions; 5404be88c2bec8d0a0cc9e1f4f0af3b3a2ff8ac4e7Marcus Hagerottimport com.google.common.base.Function; 552a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerottimport com.google.common.base.Objects; 5667a0639c912ce5bed209d791f0bf8d09853bdbbdMarcus Hagerottimport com.google.common.base.Predicate; 5767a0639c912ce5bed209d791f0bf8d09853bdbbdMarcus Hagerottimport com.google.common.collect.Collections2; 5804be88c2bec8d0a0cc9e1f4f0af3b3a2ff8ac4e7Marcus Hagerottimport com.google.common.util.concurrent.FutureCallback; 5904be88c2bec8d0a0cc9e1f4f0af3b3a2ff8ac4e7Marcus Hagerottimport com.google.common.util.concurrent.Futures; 6004be88c2bec8d0a0cc9e1f4f0af3b3a2ff8ac4e7Marcus Hagerottimport com.google.common.util.concurrent.ListenableFuture; 6104be88c2bec8d0a0cc9e1f4f0af3b3a2ff8ac4e7Marcus Hagerottimport com.google.common.util.concurrent.ListeningExecutorService; 626c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng 63ac33359ec62ff26c57da4328c2fa7b0f091b4e13Gary Maiimport java.util.ArrayList; 646c712f45c80cef426a86fa14668a935c488d0ee4Chiao Chengimport java.util.Collections; 656c712f45c80cef426a86fa14668a935c488d0ee4Chiao Chengimport java.util.List; 6604be88c2bec8d0a0cc9e1f4f0af3b3a2ff8ac4e7Marcus Hagerottimport java.util.concurrent.Callable; 6704be88c2bec8d0a0cc9e1f4f0af3b3a2ff8ac4e7Marcus Hagerottimport java.util.concurrent.Executor; 686c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng 6967a0639c912ce5bed209d791f0bf8d09853bdbbdMarcus Hagerottimport javax.annotation.Nullable; 7067a0639c912ce5bed209d791f0bf8d09853bdbbdMarcus Hagerott 716c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng/** 726c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng * Singleton holder for all parsed {@link AccountType} available on the 736c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng * system, typically filled through {@link PackageManager} queries. 746c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng */ 756c712f45c80cef426a86fa14668a935c488d0ee4Chiao Chengpublic abstract class AccountTypeManager { 766c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng static final String TAG = "AccountTypeManager"; 776c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng 786c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng private static final Object mInitializationLock = new Object(); 796c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng private static AccountTypeManager mAccountTypeManager; 806c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng 81e7a71cbbe8929a9d8a7ca0a3b5668646d49a611aMarcus Hagerott public static final String BROADCAST_ACCOUNTS_CHANGED = AccountTypeManager.class.getName() + 82e7a71cbbe8929a9d8a7ca0a3b5668646d49a611aMarcus Hagerott ".AccountsChanged"; 83e7a71cbbe8929a9d8a7ca0a3b5668646d49a611aMarcus Hagerott 84ee3d3a503553de2699285d98bc6fe7d34699a8b0Marcus Hagerott public enum AccountFilter implements Predicate<AccountInfo> { 85ee3d3a503553de2699285d98bc6fe7d34699a8b0Marcus Hagerott ALL { 86ee3d3a503553de2699285d98bc6fe7d34699a8b0Marcus Hagerott @Override 87ee3d3a503553de2699285d98bc6fe7d34699a8b0Marcus Hagerott public boolean apply(@Nullable AccountInfo input) { 88ee3d3a503553de2699285d98bc6fe7d34699a8b0Marcus Hagerott return input != null; 89ee3d3a503553de2699285d98bc6fe7d34699a8b0Marcus Hagerott } 90ee3d3a503553de2699285d98bc6fe7d34699a8b0Marcus Hagerott }, 91ee3d3a503553de2699285d98bc6fe7d34699a8b0Marcus Hagerott CONTACTS_WRITABLE { 92ee3d3a503553de2699285d98bc6fe7d34699a8b0Marcus Hagerott @Override 93ee3d3a503553de2699285d98bc6fe7d34699a8b0Marcus Hagerott public boolean apply(@Nullable AccountInfo input) { 94ee3d3a503553de2699285d98bc6fe7d34699a8b0Marcus Hagerott return input != null && input.getType().areContactsWritable(); 95ee3d3a503553de2699285d98bc6fe7d34699a8b0Marcus Hagerott } 96ee3d3a503553de2699285d98bc6fe7d34699a8b0Marcus Hagerott }, 97ee3d3a503553de2699285d98bc6fe7d34699a8b0Marcus Hagerott GROUPS_WRITABLE { 98ee3d3a503553de2699285d98bc6fe7d34699a8b0Marcus Hagerott @Override 99ee3d3a503553de2699285d98bc6fe7d34699a8b0Marcus Hagerott public boolean apply(@Nullable AccountInfo input) { 100ee3d3a503553de2699285d98bc6fe7d34699a8b0Marcus Hagerott return input != null && input.getType().isGroupMembershipEditable(); 101ee3d3a503553de2699285d98bc6fe7d34699a8b0Marcus Hagerott } 102ee3d3a503553de2699285d98bc6fe7d34699a8b0Marcus Hagerott }; 103ee3d3a503553de2699285d98bc6fe7d34699a8b0Marcus Hagerott } 104ee3d3a503553de2699285d98bc6fe7d34699a8b0Marcus Hagerott 1056c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng /** 1066c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng * Requests the singleton instance of {@link AccountTypeManager} with data bound from 1076c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng * the available authenticators. This method can safely be called from the UI thread. 1086c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng */ 1096c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng public static AccountTypeManager getInstance(Context context) { 110fac695a36b227f5591eac064ded8e8dad3398400Marcus Hagerott if (!hasRequiredPermissions(context)) { 111fac695a36b227f5591eac064ded8e8dad3398400Marcus Hagerott // Hopefully any component that depends on the values returned by this class 112fac695a36b227f5591eac064ded8e8dad3398400Marcus Hagerott // will be restarted if the permissions change. 113fac695a36b227f5591eac064ded8e8dad3398400Marcus Hagerott return EMPTY; 114fac695a36b227f5591eac064ded8e8dad3398400Marcus Hagerott } 1156c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng synchronized (mInitializationLock) { 1166c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng if (mAccountTypeManager == null) { 1176c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng context = context.getApplicationContext(); 11804be88c2bec8d0a0cc9e1f4f0af3b3a2ff8ac4e7Marcus Hagerott mAccountTypeManager = new AccountTypeManagerImpl(context); 1196c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng } 1206c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng } 1216c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng return mAccountTypeManager; 1226c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng } 1236c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng 1246c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng /** 1256c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng * Set the instance of account type manager. This is only for and should only be used by unit 1266c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng * tests. While having this method is not ideal, it's simpler than the alternative of 1276c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng * holding this as a service in the ContactsApplication context class. 1286c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng * 1296c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng * @param mockManager The mock AccountTypeManager. 1306c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng */ 1316c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng public static void setInstanceForTest(AccountTypeManager mockManager) { 1326c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng synchronized (mInitializationLock) { 1336c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng mAccountTypeManager = mockManager; 1346c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng } 1356c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng } 1366c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng 137fac695a36b227f5591eac064ded8e8dad3398400Marcus Hagerott private static final AccountTypeManager EMPTY = new AccountTypeManager() { 13804be88c2bec8d0a0cc9e1f4f0af3b3a2ff8ac4e7Marcus Hagerott 139fac695a36b227f5591eac064ded8e8dad3398400Marcus Hagerott @Override 14075895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott public ListenableFuture<List<AccountInfo>> getAccountsAsync() { 14175895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott return Futures.immediateFuture(Collections.<AccountInfo>emptyList()); 14267a0639c912ce5bed209d791f0bf8d09853bdbbdMarcus Hagerott } 14367a0639c912ce5bed209d791f0bf8d09853bdbbdMarcus Hagerott 14467a0639c912ce5bed209d791f0bf8d09853bdbbdMarcus Hagerott @Override 14575895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott public ListenableFuture<List<AccountInfo>> filterAccountsAsync( 14675895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott Predicate<AccountInfo> filter) { 14775895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott return Futures.immediateFuture(Collections.<AccountInfo>emptyList()); 14804be88c2bec8d0a0cc9e1f4f0af3b3a2ff8ac4e7Marcus Hagerott } 14904be88c2bec8d0a0cc9e1f4f0af3b3a2ff8ac4e7Marcus Hagerott 15004be88c2bec8d0a0cc9e1f4f0af3b3a2ff8ac4e7Marcus Hagerott @Override 15175895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott public AccountInfo getAccountInfoForAccount(AccountWithDataSet account) { 15275895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott return null; 153e7a71cbbe8929a9d8a7ca0a3b5668646d49a611aMarcus Hagerott } 154e7a71cbbe8929a9d8a7ca0a3b5668646d49a611aMarcus Hagerott 155e7a71cbbe8929a9d8a7ca0a3b5668646d49a611aMarcus Hagerott @Override 15656c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wang public Account getDefaultGoogleAccount() { 15756c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wang return null; 15856c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wang } 15956c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wang 16056c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wang @Override 161fac695a36b227f5591eac064ded8e8dad3398400Marcus Hagerott public AccountType getAccountType(AccountTypeWithDataSet accountTypeWithDataSet) { 162fac695a36b227f5591eac064ded8e8dad3398400Marcus Hagerott return null; 163fac695a36b227f5591eac064ded8e8dad3398400Marcus Hagerott } 164fac695a36b227f5591eac064ded8e8dad3398400Marcus Hagerott }; 165fac695a36b227f5591eac064ded8e8dad3398400Marcus Hagerott 1666c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng /** 1676c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng * Returns the list of all accounts (if contactWritableOnly is false) or just the list of 1686c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng * contact writable accounts (if contactWritableOnly is true). 169107cd7a225eccad56dfe12ca6d32908e651b27acMarcus Hagerott * 170107cd7a225eccad56dfe12ca6d32908e651b27acMarcus Hagerott * <p>TODO(mhagerott) delete this method. It's left in place to prevent build breakages when 171107cd7a225eccad56dfe12ca6d32908e651b27acMarcus Hagerott * this change is automerged. Usages of this method in downstream branches should be 172107cd7a225eccad56dfe12ca6d32908e651b27acMarcus Hagerott * replaced with an asynchronous account loading pattern</p> 173107cd7a225eccad56dfe12ca6d32908e651b27acMarcus Hagerott */ 174107cd7a225eccad56dfe12ca6d32908e651b27acMarcus Hagerott public List<AccountWithDataSet> getAccounts(boolean contactWritableOnly) { 175107cd7a225eccad56dfe12ca6d32908e651b27acMarcus Hagerott return contactWritableOnly 176107cd7a225eccad56dfe12ca6d32908e651b27acMarcus Hagerott ? blockForWritableAccounts() 177107cd7a225eccad56dfe12ca6d32908e651b27acMarcus Hagerott : AccountInfo.extractAccounts(Futures.getUnchecked(getAccountsAsync())); 178107cd7a225eccad56dfe12ca6d32908e651b27acMarcus Hagerott } 179107cd7a225eccad56dfe12ca6d32908e651b27acMarcus Hagerott 180107cd7a225eccad56dfe12ca6d32908e651b27acMarcus Hagerott /** 181107cd7a225eccad56dfe12ca6d32908e651b27acMarcus Hagerott * Returns all contact writable accounts 182107cd7a225eccad56dfe12ca6d32908e651b27acMarcus Hagerott * 183107cd7a225eccad56dfe12ca6d32908e651b27acMarcus Hagerott * <p>In general this method should be avoided. It exists to support some legacy usages of 184107cd7a225eccad56dfe12ca6d32908e651b27acMarcus Hagerott * accounts in infrequently used features where refactoring to asynchronous loading is 185107cd7a225eccad56dfe12ca6d32908e651b27acMarcus Hagerott * not justified. The chance that this will actually block is pretty low if the app has been 186107cd7a225eccad56dfe12ca6d32908e651b27acMarcus Hagerott * launched previously</p> 1876c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng */ 188107cd7a225eccad56dfe12ca6d32908e651b27acMarcus Hagerott public List<AccountWithDataSet> blockForWritableAccounts() { 189107cd7a225eccad56dfe12ca6d32908e651b27acMarcus Hagerott return AccountInfo.extractAccounts( 190107cd7a225eccad56dfe12ca6d32908e651b27acMarcus Hagerott Futures.getUnchecked(filterAccountsAsync(AccountFilter.CONTACTS_WRITABLE))); 191107cd7a225eccad56dfe12ca6d32908e651b27acMarcus Hagerott } 1926c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng 193aa0e6ffbb780316a4e6e96e64085afb6e8679867Wenyi Wang /** 19404be88c2bec8d0a0cc9e1f4f0af3b3a2ff8ac4e7Marcus Hagerott * Loads accounts in background and returns future that will complete with list of all accounts 19504be88c2bec8d0a0cc9e1f4f0af3b3a2ff8ac4e7Marcus Hagerott */ 19675895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott public abstract ListenableFuture<List<AccountInfo>> getAccountsAsync(); 19775895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott 19875895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott /** 19975895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott * Loads accounts and applies the fitler returning only for which the predicate is true 20075895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott */ 20175895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott public abstract ListenableFuture<List<AccountInfo>> filterAccountsAsync( 20275895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott Predicate<AccountInfo> filter); 20304be88c2bec8d0a0cc9e1f4f0af3b3a2ff8ac4e7Marcus Hagerott 20475895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott public abstract AccountInfo getAccountInfoForAccount(AccountWithDataSet account); 205e7a71cbbe8929a9d8a7ca0a3b5668646d49a611aMarcus Hagerott 20604be88c2bec8d0a0cc9e1f4f0af3b3a2ff8ac4e7Marcus Hagerott /** 20756c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wang * Returns the default google account. 20856c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wang */ 20956c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wang public abstract Account getDefaultGoogleAccount(); 21056c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wang 211396aab726710c557188ace4e961064a65900524aMarcus Hagerott /** 212396aab726710c557188ace4e961064a65900524aMarcus Hagerott * Returns the Google Accounts. 213396aab726710c557188ace4e961064a65900524aMarcus Hagerott * 214396aab726710c557188ace4e961064a65900524aMarcus Hagerott * <p>This method exists in addition to filterAccountsByTypeAsync because it should be safe 215396aab726710c557188ace4e961064a65900524aMarcus Hagerott * to call synchronously. 216396aab726710c557188ace4e961064a65900524aMarcus Hagerott * </p> 217396aab726710c557188ace4e961064a65900524aMarcus Hagerott */ 21875895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott public List<AccountInfo> getWritableGoogleAccounts() { 219396aab726710c557188ace4e961064a65900524aMarcus Hagerott // This implementation may block and should be overridden by the Impl class 22075895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott return Futures.getUnchecked(filterAccountsAsync(new Predicate<AccountInfo>() { 221396aab726710c557188ace4e961064a65900524aMarcus Hagerott @Override 22275895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott public boolean apply(@Nullable AccountInfo input) { 22375895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott return input.getType().areContactsWritable() && 22475895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott GoogleAccountType.ACCOUNT_TYPE.equals(input.getType().accountType); 225396aab726710c557188ace4e961064a65900524aMarcus Hagerott } 226396aab726710c557188ace4e961064a65900524aMarcus Hagerott })); 227396aab726710c557188ace4e961064a65900524aMarcus Hagerott } 228396aab726710c557188ace4e961064a65900524aMarcus Hagerott 229396aab726710c557188ace4e961064a65900524aMarcus Hagerott /** 230396aab726710c557188ace4e961064a65900524aMarcus Hagerott * Returns true if there are real accounts (not "local" account) in the list of accounts. 231396aab726710c557188ace4e961064a65900524aMarcus Hagerott */ 232396aab726710c557188ace4e961064a65900524aMarcus Hagerott public boolean hasNonLocalAccount() { 233c34812341069afae7ddd253fc45b233706b739d9Marcus Hagerott final List<AccountWithDataSet> allAccounts = 234c34812341069afae7ddd253fc45b233706b739d9Marcus Hagerott AccountInfo.extractAccounts(Futures.getUnchecked(getAccountsAsync())); 235396aab726710c557188ace4e961064a65900524aMarcus Hagerott if (allAccounts == null || allAccounts.size() == 0) { 236396aab726710c557188ace4e961064a65900524aMarcus Hagerott return false; 237396aab726710c557188ace4e961064a65900524aMarcus Hagerott } 238396aab726710c557188ace4e961064a65900524aMarcus Hagerott if (allAccounts.size() > 1) { 239396aab726710c557188ace4e961064a65900524aMarcus Hagerott return true; 240396aab726710c557188ace4e961064a65900524aMarcus Hagerott } 241396aab726710c557188ace4e961064a65900524aMarcus Hagerott return !allAccounts.get(0).isNullAccount(); 242396aab726710c557188ace4e961064a65900524aMarcus Hagerott } 243396aab726710c557188ace4e961064a65900524aMarcus Hagerott 24456c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wang static Account getDefaultGoogleAccount(AccountManager accountManager, 24556c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wang SharedPreferences prefs, String defaultAccountKey) { 24656c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wang // Get all the google accounts on the device 24756c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wang final Account[] accounts = accountManager.getAccountsByType( 24856c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wang GoogleAccountType.ACCOUNT_TYPE); 24956c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wang if (accounts == null || accounts.length == 0) { 25056c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wang return null; 25156c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wang } 25256c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wang 25356c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wang // Get the default account from preferences 25456c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wang final String defaultAccount = prefs.getString(defaultAccountKey, null); 25556c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wang final AccountWithDataSet accountWithDataSet = defaultAccount == null ? null : 25656c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wang AccountWithDataSet.unstringify(defaultAccount); 25756c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wang 25856c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wang // Look for an account matching the one from preferences 25956c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wang if (accountWithDataSet != null) { 26056c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wang for (int i = 0; i < accounts.length; i++) { 26156c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wang if (TextUtils.equals(accountWithDataSet.name, accounts[i].name) 26256c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wang && TextUtils.equals(accountWithDataSet.type, accounts[i].type)) { 26356c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wang return accounts[i]; 26456c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wang } 26556c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wang } 26656c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wang } 26756c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wang 26856c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wang // Just return the first one 26956c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wang return accounts[0]; 27056c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wang } 27156c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wang 2726c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng public abstract AccountType getAccountType(AccountTypeWithDataSet accountTypeWithDataSet); 2736c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng 2746c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng public final AccountType getAccountType(String accountType, String dataSet) { 2756c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng return getAccountType(AccountTypeWithDataSet.get(accountType, dataSet)); 2766c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng } 2776c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng 2786c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng public final AccountType getAccountTypeForAccount(AccountWithDataSet account) { 2792ae200dc7b2995f6758887cce8dedf563b3f3aa3Jay Shrauner if (account != null) { 2802ae200dc7b2995f6758887cce8dedf563b3f3aa3Jay Shrauner return getAccountType(account.getAccountTypeWithDataSet()); 2812ae200dc7b2995f6758887cce8dedf563b3f3aa3Jay Shrauner } 2822ae200dc7b2995f6758887cce8dedf563b3f3aa3Jay Shrauner return getAccountType(null, null); 2836c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng } 2846c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng 2856c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng /** 2866c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng * Find the best {@link DataKind} matching the requested 2876c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng * {@link AccountType#accountType}, {@link AccountType#dataSet}, and {@link DataKind#mimeType}. 2886c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng * If no direct match found, we try searching {@link FallbackAccountType}. 2896c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng */ 2906c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng public DataKind getKindOrFallback(AccountType type, String mimeType) { 2916c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng return type == null ? null : type.getKindForMimetype(mimeType); 2926c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng } 2936c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng 2946c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng /** 295c34812341069afae7ddd253fc45b233706b739d9Marcus Hagerott * Returns whether the specified account still exists 2966c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng */ 297c34812341069afae7ddd253fc45b233706b739d9Marcus Hagerott public boolean exists(AccountWithDataSet account) { 298c34812341069afae7ddd253fc45b233706b739d9Marcus Hagerott final List<AccountWithDataSet> accounts = 299c34812341069afae7ddd253fc45b233706b739d9Marcus Hagerott AccountInfo.extractAccounts(Futures.getUnchecked(getAccountsAsync())); 300c34812341069afae7ddd253fc45b233706b739d9Marcus Hagerott return accounts.contains(account); 301c34812341069afae7ddd253fc45b233706b739d9Marcus Hagerott } 302c34812341069afae7ddd253fc45b233706b739d9Marcus Hagerott 303c34812341069afae7ddd253fc45b233706b739d9Marcus Hagerott /** 304c34812341069afae7ddd253fc45b233706b739d9Marcus Hagerott * Returns whether the specified account is writable 305c34812341069afae7ddd253fc45b233706b739d9Marcus Hagerott * 306c34812341069afae7ddd253fc45b233706b739d9Marcus Hagerott * <p>This checks that the account still exists and that 307c34812341069afae7ddd253fc45b233706b739d9Marcus Hagerott * {@link AccountType#areContactsWritable()} is true</p> 308c34812341069afae7ddd253fc45b233706b739d9Marcus Hagerott */ 309c34812341069afae7ddd253fc45b233706b739d9Marcus Hagerott public boolean isWritable(AccountWithDataSet account) { 310c34812341069afae7ddd253fc45b233706b739d9Marcus Hagerott return exists(account) && getAccountInfoForAccount(account).getType().areContactsWritable(); 3116c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng } 312fac695a36b227f5591eac064ded8e8dad3398400Marcus Hagerott 313596eb7e7cefd97fddc738c0600c24b08cbba827fMarcus Hagerott public boolean hasGoogleAccount() { 314596eb7e7cefd97fddc738c0600c24b08cbba827fMarcus Hagerott return getDefaultGoogleAccount() != null; 315596eb7e7cefd97fddc738c0600c24b08cbba827fMarcus Hagerott } 316596eb7e7cefd97fddc738c0600c24b08cbba827fMarcus Hagerott 317fac695a36b227f5591eac064ded8e8dad3398400Marcus Hagerott private static boolean hasRequiredPermissions(Context context) { 318fac695a36b227f5591eac064ded8e8dad3398400Marcus Hagerott final boolean canGetAccounts = ContextCompat.checkSelfPermission(context, 319fac695a36b227f5591eac064ded8e8dad3398400Marcus Hagerott android.Manifest.permission.GET_ACCOUNTS) == PackageManager.PERMISSION_GRANTED; 320fac695a36b227f5591eac064ded8e8dad3398400Marcus Hagerott final boolean canReadContacts = ContextCompat.checkSelfPermission(context, 321fac695a36b227f5591eac064ded8e8dad3398400Marcus Hagerott android.Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED; 322fac695a36b227f5591eac064ded8e8dad3398400Marcus Hagerott return canGetAccounts && canReadContacts; 323fac695a36b227f5591eac064ded8e8dad3398400Marcus Hagerott } 324fac695a36b227f5591eac064ded8e8dad3398400Marcus Hagerott 32575895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott public static Predicate<AccountInfo> writableFilter() { 326ee3d3a503553de2699285d98bc6fe7d34699a8b0Marcus Hagerott return AccountFilter.CONTACTS_WRITABLE; 327e7a71cbbe8929a9d8a7ca0a3b5668646d49a611aMarcus Hagerott } 328e7a71cbbe8929a9d8a7ca0a3b5668646d49a611aMarcus Hagerott 32975895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott public static Predicate<AccountInfo> groupWritableFilter() { 330ee3d3a503553de2699285d98bc6fe7d34699a8b0Marcus Hagerott return AccountFilter.GROUPS_WRITABLE; 331e7a71cbbe8929a9d8a7ca0a3b5668646d49a611aMarcus Hagerott } 332aa0e6ffbb780316a4e6e96e64085afb6e8679867Wenyi Wang} 333aa0e6ffbb780316a4e6e96e64085afb6e8679867Wenyi Wang 3346c712f45c80cef426a86fa14668a935c488d0ee4Chiao Chengclass AccountTypeManagerImpl extends AccountTypeManager 3356c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng implements OnAccountsUpdateListener, SyncStatusObserver { 3366c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng 3372a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott private final Context mContext; 3382a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott private final AccountManager mAccountManager; 3392a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott private final DeviceLocalAccountLocator mLocalAccountLocator; 3402a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott private final Executor mMainThreadExecutor; 3412a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott private final ListeningExecutorService mExecutor; 342e7a71cbbe8929a9d8a7ca0a3b5668646d49a611aMarcus Hagerott private AccountTypeProvider mTypeProvider; 3436c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng 3442a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott private final AccountType mFallbackAccountType; 3456c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng 346c2093f312f71e730e1cc4daaa305782fda394215Marcus Hagerott private ListenableFuture<List<AccountWithDataSet>> mLocalAccountsFuture; 347c2093f312f71e730e1cc4daaa305782fda394215Marcus Hagerott private ListenableFuture<AccountTypeProvider> mAccountTypesFuture; 348c2093f312f71e730e1cc4daaa305782fda394215Marcus Hagerott 3492a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott private List<AccountWithDataSet> mLocalAccounts = new ArrayList<>(); 3502a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott private List<AccountWithDataSet> mAccountManagerAccounts = new ArrayList<>(); 3516c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng 3526c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper()); 3536c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng 3542a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott private final Function<AccountTypeProvider, List<AccountWithDataSet>> mAccountsExtractor = 3552a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott new Function<AccountTypeProvider, List<AccountWithDataSet>>() { 3562a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott @Nullable 3572a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott @Override 3582a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott public List<AccountWithDataSet> apply(@Nullable AccountTypeProvider typeProvider) { 3592a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott return getAccountsWithDataSets(mAccountManager.getAccounts(), typeProvider); 3602a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott } 3612a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott }; 3622a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott 3632a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott 3646c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 3656c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng @Override 3666c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng public void onReceive(Context context, Intent intent) { 3672a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott // Don't use reloadAccountTypesIfNeeded when packages change in case a contacts.xml 3682a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott // was updated. 36904be88c2bec8d0a0cc9e1f4f0af3b3a2ff8ac4e7Marcus Hagerott reloadAccountTypes(); 3706c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng } 3716c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng }; 3726c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng 3736c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng /** 3746c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng * Internal constructor that only performs initial parsing. 3756c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng */ 37604be88c2bec8d0a0cc9e1f4f0af3b3a2ff8ac4e7Marcus Hagerott public AccountTypeManagerImpl(Context context) { 3776c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng mContext = context; 378c2093f312f71e730e1cc4daaa305782fda394215Marcus Hagerott mLocalAccountLocator = DeviceLocalAccountLocator.create(context); 379e7a71cbbe8929a9d8a7ca0a3b5668646d49a611aMarcus Hagerott mTypeProvider = new AccountTypeProvider(context); 3806c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng mFallbackAccountType = new FallbackAccountType(context); 3816c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng 382413589f0b9279e06d8913761cdcf03c8fef7ffd8Ihab Awad mAccountManager = AccountManager.get(mContext); 3836c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng 38404be88c2bec8d0a0cc9e1f4f0af3b3a2ff8ac4e7Marcus Hagerott mExecutor = ContactsExecutors.getDefaultThreadPoolExecutor(); 38504be88c2bec8d0a0cc9e1f4f0af3b3a2ff8ac4e7Marcus Hagerott mMainThreadExecutor = ContactsExecutors.newHandlerExecutor(mMainThreadHandler); 3866c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng 3876c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng // Request updates when packages or accounts change 3886c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED); 3896c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng filter.addAction(Intent.ACTION_PACKAGE_REMOVED); 3906c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng filter.addAction(Intent.ACTION_PACKAGE_CHANGED); 3916c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng filter.addDataScheme("package"); 3926c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng mContext.registerReceiver(mBroadcastReceiver, filter); 3936c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng IntentFilter sdFilter = new IntentFilter(); 3946c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); 3956c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); 3966c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng mContext.registerReceiver(mBroadcastReceiver, sdFilter); 3976c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng 3986c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng // Request updates when locale is changed so that the order of each field will 3996c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng // be able to be changed on the locale change. 4006c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng filter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED); 4016c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng mContext.registerReceiver(mBroadcastReceiver, filter); 4026c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng 40304be88c2bec8d0a0cc9e1f4f0af3b3a2ff8ac4e7Marcus Hagerott mAccountManager.addOnAccountsUpdatedListener(this, mMainThreadHandler, false); 4046c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng 4056c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng ContentResolver.addStatusChangeListener(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS, this); 4066c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng 407ffcb31f6ece6257d0bc50aa572de0d4b93c82e97Walter Jang if (Flags.getInstance().getBoolean(Experiments.CP2_DEVICE_ACCOUNT_DETECTION_ENABLED)) { 408511504f977e83a60049bc051ee7e6064ca2b0264Marcus Hagerott // Observe changes to RAW_CONTACTS so that we will update the list of "Device" accounts 409511504f977e83a60049bc051ee7e6064ca2b0264Marcus Hagerott // if a new device contact is added. 410511504f977e83a60049bc051ee7e6064ca2b0264Marcus Hagerott mContext.getContentResolver().registerContentObserver( 411511504f977e83a60049bc051ee7e6064ca2b0264Marcus Hagerott ContactsContract.RawContacts.CONTENT_URI, /* notifyDescendents */ true, 41204be88c2bec8d0a0cc9e1f4f0af3b3a2ff8ac4e7Marcus Hagerott new ContentObserver(mMainThreadHandler) { 413511504f977e83a60049bc051ee7e6064ca2b0264Marcus Hagerott @Override 414511504f977e83a60049bc051ee7e6064ca2b0264Marcus Hagerott public boolean deliverSelfNotifications() { 415511504f977e83a60049bc051ee7e6064ca2b0264Marcus Hagerott return true; 416511504f977e83a60049bc051ee7e6064ca2b0264Marcus Hagerott } 417511504f977e83a60049bc051ee7e6064ca2b0264Marcus Hagerott 418511504f977e83a60049bc051ee7e6064ca2b0264Marcus Hagerott @Override 419511504f977e83a60049bc051ee7e6064ca2b0264Marcus Hagerott public void onChange(boolean selfChange) { 420c2093f312f71e730e1cc4daaa305782fda394215Marcus Hagerott reloadLocalAccounts(); 421511504f977e83a60049bc051ee7e6064ca2b0264Marcus Hagerott } 422511504f977e83a60049bc051ee7e6064ca2b0264Marcus Hagerott 423511504f977e83a60049bc051ee7e6064ca2b0264Marcus Hagerott @Override 424511504f977e83a60049bc051ee7e6064ca2b0264Marcus Hagerott public void onChange(boolean selfChange, Uri uri) { 425c2093f312f71e730e1cc4daaa305782fda394215Marcus Hagerott reloadLocalAccounts(); 426511504f977e83a60049bc051ee7e6064ca2b0264Marcus Hagerott } 427511504f977e83a60049bc051ee7e6064ca2b0264Marcus Hagerott }); 428511504f977e83a60049bc051ee7e6064ca2b0264Marcus Hagerott } 429e7a71cbbe8929a9d8a7ca0a3b5668646d49a611aMarcus Hagerott loadAccountTypes(); 4306c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng } 4316c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng 4326c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng @Override 4336c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng public void onStatusChanged(int which) { 4342a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott reloadAccountTypesIfNeeded(); 4356c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng } 4366c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng 4379a679e742e9e738d659f6f8a566c1db7a252f77fMarcus Hagerott /* This notification will arrive on the UI thread */ 4386c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng public void onAccountsUpdated(Account[] accounts) { 4394fabad6a2949f028f575c1cbde6b01368cd78d60Marcus Hagerott reloadLocalAccounts(); 4402a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott maybeNotifyAccountsUpdated(mAccountManagerAccounts, 4412a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott getAccountsWithDataSets(accounts, mTypeProvider)); 4422a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott } 4432a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott 4442a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott private void maybeNotifyAccountsUpdated(List<AccountWithDataSet> current, 4452a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott List<AccountWithDataSet> update) { 4462a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott if (Objects.equal(current, update)) { 4472a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott return; 4482a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott } 4492a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott current.clear(); 4502a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott current.addAll(update); 4512a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott notifyAccountsChanged(); 4526c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng } 4536c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng 4542a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott private void notifyAccountsChanged() { 45504be88c2bec8d0a0cc9e1f4f0af3b3a2ff8ac4e7Marcus Hagerott ContactListFilterController.getInstance(mContext).checkFilterValidity(true); 456e7a71cbbe8929a9d8a7ca0a3b5668646d49a611aMarcus Hagerott LocalBroadcastManager.getInstance(mContext).sendBroadcast( 457e7a71cbbe8929a9d8a7ca0a3b5668646d49a611aMarcus Hagerott new Intent(BROADCAST_ACCOUNTS_CHANGED)); 4586c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng } 4596c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng 46004be88c2bec8d0a0cc9e1f4f0af3b3a2ff8ac4e7Marcus Hagerott private synchronized void startLoadingIfNeeded() { 461c2093f312f71e730e1cc4daaa305782fda394215Marcus Hagerott if (mTypeProvider == null && mAccountTypesFuture == null) { 4622a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott reloadAccountTypesIfNeeded(); 4636c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng } 464c2093f312f71e730e1cc4daaa305782fda394215Marcus Hagerott if (mLocalAccountsFuture == null) { 465c2093f312f71e730e1cc4daaa305782fda394215Marcus Hagerott reloadLocalAccounts(); 466c2093f312f71e730e1cc4daaa305782fda394215Marcus Hagerott } 46704be88c2bec8d0a0cc9e1f4f0af3b3a2ff8ac4e7Marcus Hagerott } 4686c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng 4692a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott private synchronized void loadAccountTypes() { 470e7a71cbbe8929a9d8a7ca0a3b5668646d49a611aMarcus Hagerott mTypeProvider = new AccountTypeProvider(mContext); 4716c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng 472c2093f312f71e730e1cc4daaa305782fda394215Marcus Hagerott mAccountTypesFuture = mExecutor.submit(new Callable<AccountTypeProvider>() { 47304be88c2bec8d0a0cc9e1f4f0af3b3a2ff8ac4e7Marcus Hagerott @Override 47404be88c2bec8d0a0cc9e1f4f0af3b3a2ff8ac4e7Marcus Hagerott public AccountTypeProvider call() throws Exception { 4752a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott // This will request the AccountType for each Account forcing them to be loaded 4762a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott getAccountsWithDataSets(mAccountManager.getAccounts(), mTypeProvider); 477e7a71cbbe8929a9d8a7ca0a3b5668646d49a611aMarcus Hagerott return mTypeProvider; 478fac695a36b227f5591eac064ded8e8dad3398400Marcus Hagerott } 47904be88c2bec8d0a0cc9e1f4f0af3b3a2ff8ac4e7Marcus Hagerott }); 480e7a71cbbe8929a9d8a7ca0a3b5668646d49a611aMarcus Hagerott } 481e7a71cbbe8929a9d8a7ca0a3b5668646d49a611aMarcus Hagerott 4822a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott private FutureCallback<List<AccountWithDataSet>> newAccountsUpdatedCallback( 4832a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott final List<AccountWithDataSet> currentAccounts) { 4842a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott return new FutureCallback<List<AccountWithDataSet>>() { 4852a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott @Override 4862a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott public void onSuccess(List<AccountWithDataSet> result) { 4872a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott maybeNotifyAccountsUpdated(currentAccounts, result); 4882a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott } 4892a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott 4902a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott @Override 4912a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott public void onFailure(Throwable t) { 4922a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott } 4932a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott }; 4942a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott } 4952a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott 4962a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott private synchronized void reloadAccountTypesIfNeeded() { 4972a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott if (mTypeProvider == null || mTypeProvider.shouldUpdate( 4982a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott mAccountManager.getAuthenticatorTypes(), ContentResolver.getSyncAdapterTypes())) { 4992a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott reloadAccountTypes(); 5002a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott } 5012a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott } 5022a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott 503c2093f312f71e730e1cc4daaa305782fda394215Marcus Hagerott private synchronized void reloadAccountTypes() { 504e7a71cbbe8929a9d8a7ca0a3b5668646d49a611aMarcus Hagerott loadAccountTypes(); 5052a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott Futures.addCallback( 5062a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott Futures.transform(mAccountTypesFuture, mAccountsExtractor), 5072a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott newAccountsUpdatedCallback(mAccountManagerAccounts), 5082a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott mMainThreadExecutor); 509c2093f312f71e730e1cc4daaa305782fda394215Marcus Hagerott } 5106c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng 511c2093f312f71e730e1cc4daaa305782fda394215Marcus Hagerott private synchronized void loadLocalAccounts() { 512c2093f312f71e730e1cc4daaa305782fda394215Marcus Hagerott mLocalAccountsFuture = mExecutor.submit(new Callable<List<AccountWithDataSet>>() { 51304be88c2bec8d0a0cc9e1f4f0af3b3a2ff8ac4e7Marcus Hagerott @Override 514c2093f312f71e730e1cc4daaa305782fda394215Marcus Hagerott public List<AccountWithDataSet> call() throws Exception { 515c2093f312f71e730e1cc4daaa305782fda394215Marcus Hagerott return mLocalAccountLocator.getDeviceLocalAccounts(); 5166c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng } 517c2093f312f71e730e1cc4daaa305782fda394215Marcus Hagerott }); 518c2093f312f71e730e1cc4daaa305782fda394215Marcus Hagerott } 519c2093f312f71e730e1cc4daaa305782fda394215Marcus Hagerott 5202a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott private synchronized void reloadLocalAccounts() { 521c2093f312f71e730e1cc4daaa305782fda394215Marcus Hagerott loadLocalAccounts(); 5222a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott Futures.addCallback(mLocalAccountsFuture, newAccountsUpdatedCallback(mLocalAccounts), 5232a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott mMainThreadExecutor); 5246c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng } 5256c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng 52667a0639c912ce5bed209d791f0bf8d09853bdbbdMarcus Hagerott @Override 52775895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott public ListenableFuture<List<AccountInfo>> getAccountsAsync() { 52875895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott return getAllAccountsAsyncInternal(); 52904be88c2bec8d0a0cc9e1f4f0af3b3a2ff8ac4e7Marcus Hagerott } 53004be88c2bec8d0a0cc9e1f4f0af3b3a2ff8ac4e7Marcus Hagerott 5312a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott private synchronized ListenableFuture<List<AccountInfo>> getAllAccountsAsyncInternal() { 53204be88c2bec8d0a0cc9e1f4f0af3b3a2ff8ac4e7Marcus Hagerott startLoadingIfNeeded(); 53375895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott final AccountTypeProvider typeProvider = mTypeProvider; 5342a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott final ListenableFuture<List<List<AccountWithDataSet>>> all = 5352a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott Futures.nonCancellationPropagating( 5362a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott Futures.successfulAsList( 5372a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott Futures.transform(mAccountTypesFuture, mAccountsExtractor), 5382a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott mLocalAccountsFuture)); 539c2093f312f71e730e1cc4daaa305782fda394215Marcus Hagerott 5402a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott return Futures.transform(all, new Function<List<List<AccountWithDataSet>>, 54175895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott List<AccountInfo>>() { 5422a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott @Nullable 543c2093f312f71e730e1cc4daaa305782fda394215Marcus Hagerott @Override 5442a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott public List<AccountInfo> apply(@Nullable List<List<AccountWithDataSet>> input) { 54575895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott // input.get(0) contains accounts from AccountManager 54675895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott // input.get(1) contains device local accounts 54775895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott Preconditions.checkArgument(input.size() == 2, 54875895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott "List should have exactly 2 elements"); 54975895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott 5502a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott final List<AccountInfo> result = new ArrayList<>(); 5512a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott for (AccountWithDataSet account : input.get(0)) { 5522a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott result.add( 5532a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott typeProvider.getTypeForAccount(account).wrapAccount(mContext, account)); 5542a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott } 5552a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott 5562a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott for (AccountWithDataSet account : input.get(1)) { 5572a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott result.add( 5582a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott typeProvider.getTypeForAccount(account).wrapAccount(mContext, account)); 559c2093f312f71e730e1cc4daaa305782fda394215Marcus Hagerott } 56075895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott AccountInfo.sortAccounts(null, result); 561c2093f312f71e730e1cc4daaa305782fda394215Marcus Hagerott return result; 562c2093f312f71e730e1cc4daaa305782fda394215Marcus Hagerott } 563c2093f312f71e730e1cc4daaa305782fda394215Marcus Hagerott }); 564e7a71cbbe8929a9d8a7ca0a3b5668646d49a611aMarcus Hagerott } 565e7a71cbbe8929a9d8a7ca0a3b5668646d49a611aMarcus Hagerott 56675895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott @Override 56775895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott public ListenableFuture<List<AccountInfo>> filterAccountsAsync( 56875895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott final Predicate<AccountInfo> filter) { 56975895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott return Futures.transform(getAllAccountsAsyncInternal(), new Function<List<AccountInfo>, 57075895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott List<AccountInfo>>() { 57175895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott @Override 57275895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott public List<AccountInfo> apply(List<AccountInfo> input) { 57375895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott return new ArrayList<>(Collections2.filter(input, filter)); 57475895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott } 57575895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott }, mExecutor); 57675895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott } 57775895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott 57875895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott @Override 57975895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott public AccountInfo getAccountInfoForAccount(AccountWithDataSet account) { 5804bd50d69d2b8934dbd4cbd634ad83807d9b02735Marcus Hagerott if (account == null) { 5814bd50d69d2b8934dbd4cbd634ad83807d9b02735Marcus Hagerott return null; 5824bd50d69d2b8934dbd4cbd634ad83807d9b02735Marcus Hagerott } 5834fbcd1943f493524e96db648e2a6957689fcc83dMarcus Hagerott AccountType type = mTypeProvider.getTypeForAccount(account); 58475895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott if (type == null) { 5854fbcd1943f493524e96db648e2a6957689fcc83dMarcus Hagerott type = mFallbackAccountType; 58675895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott } 58775895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott return type.wrapAccount(mContext, account); 58875895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott } 58975895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott 5902a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott private List<AccountWithDataSet> getAccountsWithDataSets(Account[] accounts, 5912a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott AccountTypeProvider typeProvider) { 5922a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott List<AccountWithDataSet> result = new ArrayList<>(); 59304be88c2bec8d0a0cc9e1f4f0af3b3a2ff8ac4e7Marcus Hagerott for (Account account : accounts) { 59475895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott final List<AccountType> types = typeProvider.getAccountTypes(account.type); 59504be88c2bec8d0a0cc9e1f4f0af3b3a2ff8ac4e7Marcus Hagerott for (AccountType type : types) { 5962a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott result.add(new AccountWithDataSet( 5972a4673a93880c43d9dda547e7bdc5ee35a1b025cMarcus Hagerott account.name, account.type, type.dataSet)); 59804be88c2bec8d0a0cc9e1f4f0af3b3a2ff8ac4e7Marcus Hagerott } 59904be88c2bec8d0a0cc9e1f4f0af3b3a2ff8ac4e7Marcus Hagerott } 60004be88c2bec8d0a0cc9e1f4f0af3b3a2ff8ac4e7Marcus Hagerott return result; 60104be88c2bec8d0a0cc9e1f4f0af3b3a2ff8ac4e7Marcus Hagerott } 60204be88c2bec8d0a0cc9e1f4f0af3b3a2ff8ac4e7Marcus Hagerott 6036c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng /** 60456c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wang * Returns the default google account specified in preferences, the first google account 60556c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wang * if it is not specified in preferences or is no longer on the device, and null otherwise. 60656c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wang */ 60756c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wang @Override 60856c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wang public Account getDefaultGoogleAccount() { 60956c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wang final SharedPreferences sharedPreferences = 61056c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wang mContext.getSharedPreferences(mContext.getPackageName(), Context.MODE_PRIVATE); 61156c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wang final String defaultAccountKey = 61256c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wang mContext.getResources().getString(R.string.contact_editor_default_account_key); 613396aab726710c557188ace4e961064a65900524aMarcus Hagerott return getDefaultGoogleAccount(mAccountManager, sharedPreferences, defaultAccountKey); 614396aab726710c557188ace4e961064a65900524aMarcus Hagerott } 615396aab726710c557188ace4e961064a65900524aMarcus Hagerott 616396aab726710c557188ace4e961064a65900524aMarcus Hagerott @Override 61775895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott public List<AccountInfo> getWritableGoogleAccounts() { 618396aab726710c557188ace4e961064a65900524aMarcus Hagerott final Account[] googleAccounts = 619396aab726710c557188ace4e961064a65900524aMarcus Hagerott mAccountManager.getAccountsByType(GoogleAccountType.ACCOUNT_TYPE); 62075895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott final List<AccountInfo> result = new ArrayList<>(); 621396aab726710c557188ace4e961064a65900524aMarcus Hagerott for (Account account : googleAccounts) { 62275895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott final AccountWithDataSet accountWithDataSet = new AccountWithDataSet( 62375895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott account.name, account.type, null); 62475895e73379aa26a3d4135c772af4ecb8a79b4c9Marcus Hagerott final AccountType type = mTypeProvider.getTypeForAccount(accountWithDataSet); 625032560017404fd778dfb8a72674eb5e9fd35332fNicholas Sauer if (type != null) { 626032560017404fd778dfb8a72674eb5e9fd35332fNicholas Sauer // Accounts with a dataSet (e.g. Google plus accounts) are not writable. 627032560017404fd778dfb8a72674eb5e9fd35332fNicholas Sauer result.add(type.wrapAccount(mContext, accountWithDataSet)); 628032560017404fd778dfb8a72674eb5e9fd35332fNicholas Sauer } 629396aab726710c557188ace4e961064a65900524aMarcus Hagerott } 630396aab726710c557188ace4e961064a65900524aMarcus Hagerott return result; 631396aab726710c557188ace4e961064a65900524aMarcus Hagerott } 632396aab726710c557188ace4e961064a65900524aMarcus Hagerott 633c34812341069afae7ddd253fc45b233706b739d9Marcus Hagerott /** 634c34812341069afae7ddd253fc45b233706b739d9Marcus Hagerott * Returns true if there are real accounts (not "local" account) in the list of accounts. 635c34812341069afae7ddd253fc45b233706b739d9Marcus Hagerott * 636c34812341069afae7ddd253fc45b233706b739d9Marcus Hagerott * <p>This is overriden for performance since the default implementation blocks until all 637c34812341069afae7ddd253fc45b233706b739d9Marcus Hagerott * accounts are loaded 638c34812341069afae7ddd253fc45b233706b739d9Marcus Hagerott * </p> 639c34812341069afae7ddd253fc45b233706b739d9Marcus Hagerott */ 640396aab726710c557188ace4e961064a65900524aMarcus Hagerott @Override 641396aab726710c557188ace4e961064a65900524aMarcus Hagerott public boolean hasNonLocalAccount() { 642396aab726710c557188ace4e961064a65900524aMarcus Hagerott final Account[] accounts = mAccountManager.getAccounts(); 6437778080136f70e4f5ac90a3bb8281addf5898894Marcus Hagerott if (accounts == null) { 6447778080136f70e4f5ac90a3bb8281addf5898894Marcus Hagerott return false; 6457778080136f70e4f5ac90a3bb8281addf5898894Marcus Hagerott } 6467778080136f70e4f5ac90a3bb8281addf5898894Marcus Hagerott for (Account account : accounts) { 6477778080136f70e4f5ac90a3bb8281addf5898894Marcus Hagerott if (mTypeProvider.supportsContactsSyncing(account.type)) { 6487778080136f70e4f5ac90a3bb8281addf5898894Marcus Hagerott return true; 6497778080136f70e4f5ac90a3bb8281addf5898894Marcus Hagerott } 6507778080136f70e4f5ac90a3bb8281addf5898894Marcus Hagerott } 6517778080136f70e4f5ac90a3bb8281addf5898894Marcus Hagerott return false; 65256c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wang } 65356c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wang 65456c8a0cce9ea98e0f088e74474a57968a02810abWenyi Wang /** 6556c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng * Find the best {@link DataKind} matching the requested 6566c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng * {@link AccountType#accountType}, {@link AccountType#dataSet}, and {@link DataKind#mimeType}. 6576c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng * If no direct match found, we try searching {@link FallbackAccountType}. 6586c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng */ 6596c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng @Override 6606c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng public DataKind getKindOrFallback(AccountType type, String mimeType) { 6616c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng DataKind kind = null; 6626c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng 6636c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng // Try finding account type and kind matching request 6646c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng if (type != null) { 6656c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng kind = type.getKindForMimetype(mimeType); 6666c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng } 6676c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng 6686c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng if (kind == null) { 6696c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng // Nothing found, so try fallback as last resort 6706c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng kind = mFallbackAccountType.getKindForMimetype(mimeType); 6716c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng } 6726c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng 6736c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng if (kind == null) { 6745df737617966dc1a3e3150443a30eddb3a1ac057Chiao Cheng if (Log.isLoggable(TAG, Log.DEBUG)) { 6755df737617966dc1a3e3150443a30eddb3a1ac057Chiao Cheng Log.d(TAG, "Unknown type=" + type + ", mime=" + mimeType); 6765df737617966dc1a3e3150443a30eddb3a1ac057Chiao Cheng } 6776c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng } 6786c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng 6796c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng return kind; 6806c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng } 6816c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng 6826c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng /** 683c34812341069afae7ddd253fc45b233706b739d9Marcus Hagerott * Returns whether the account still exists on the device 684c34812341069afae7ddd253fc45b233706b739d9Marcus Hagerott * 685c34812341069afae7ddd253fc45b233706b739d9Marcus Hagerott * <p>This is overridden for performance. The default implementation loads all accounts then 686c34812341069afae7ddd253fc45b233706b739d9Marcus Hagerott * searches through them for specified. This implementation will only load the types for the 687c34812341069afae7ddd253fc45b233706b739d9Marcus Hagerott * specified AccountType (it may still require blocking on IO in some cases but it shouldn't 688c34812341069afae7ddd253fc45b233706b739d9Marcus Hagerott * be as bad as blocking for all accounts). 689c34812341069afae7ddd253fc45b233706b739d9Marcus Hagerott * </p> 690c34812341069afae7ddd253fc45b233706b739d9Marcus Hagerott */ 691c34812341069afae7ddd253fc45b233706b739d9Marcus Hagerott @Override 692c34812341069afae7ddd253fc45b233706b739d9Marcus Hagerott public boolean exists(AccountWithDataSet account) { 693c34812341069afae7ddd253fc45b233706b739d9Marcus Hagerott final Account[] accounts = mAccountManager.getAccountsByType(account.type); 694c34812341069afae7ddd253fc45b233706b739d9Marcus Hagerott for (Account existingAccount : accounts) { 695c34812341069afae7ddd253fc45b233706b739d9Marcus Hagerott if (existingAccount.name.equals(account.name)) { 696c34812341069afae7ddd253fc45b233706b739d9Marcus Hagerott return mTypeProvider.getTypeForAccount(account) != null; 697c34812341069afae7ddd253fc45b233706b739d9Marcus Hagerott } 698c34812341069afae7ddd253fc45b233706b739d9Marcus Hagerott } 699c34812341069afae7ddd253fc45b233706b739d9Marcus Hagerott return false; 700c34812341069afae7ddd253fc45b233706b739d9Marcus Hagerott } 701c34812341069afae7ddd253fc45b233706b739d9Marcus Hagerott 702c34812341069afae7ddd253fc45b233706b739d9Marcus Hagerott /** 7036c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng * Return {@link AccountType} for the given account type and data set. 7046c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng */ 7056c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng @Override 7066c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng public AccountType getAccountType(AccountTypeWithDataSet accountTypeWithDataSet) { 7074fbcd1943f493524e96db648e2a6957689fcc83dMarcus Hagerott final AccountType type = mTypeProvider.getType( 70804be88c2bec8d0a0cc9e1f4f0af3b3a2ff8ac4e7Marcus Hagerott accountTypeWithDataSet.accountType, accountTypeWithDataSet.dataSet); 7094fbcd1943f493524e96db648e2a6957689fcc83dMarcus Hagerott return type != null ? type : mFallbackAccountType; 7106c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng } 7116c712f45c80cef426a86fa14668a935c488d0ee4Chiao Cheng} 712