1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.contacts.model; 17 18 import android.accounts.Account; 19 import android.accounts.AccountManager; 20 import android.content.Context; 21 import android.database.Cursor; 22 import android.provider.ContactsContract; 23 24 import com.android.contacts.Experiments; 25 import com.android.contacts.model.account.AccountWithDataSet; 26 import com.android.contacts.model.account.GoogleAccountType; 27 import com.android.contactsbind.ObjectFactory; 28 import com.android.contactsbind.experiments.Flags; 29 30 import java.util.Collections; 31 import java.util.HashSet; 32 import java.util.List; 33 import java.util.Set; 34 35 /** 36 * Attempts to detect accounts for device contacts 37 */ 38 public abstract class DeviceLocalAccountLocator { 39 40 /** 41 * Returns a list of device local accounts 42 */ getDeviceLocalAccounts()43 public abstract List<AccountWithDataSet> getDeviceLocalAccounts(); 44 45 // This works on Nexus and AOSP because the local device account is the null account but most 46 // OEMs have a special account name and type for their device account. 47 public static final DeviceLocalAccountLocator NULL_ONLY = new DeviceLocalAccountLocator() { 48 @Override 49 public List<AccountWithDataSet> getDeviceLocalAccounts() { 50 return Collections.singletonList(AccountWithDataSet.getNullAccount()); 51 } 52 }; 53 create(Context context, Set<String> knownAccountTypes)54 public static DeviceLocalAccountLocator create(Context context, 55 Set<String> knownAccountTypes) { 56 if (Flags.getInstance().getBoolean(Experiments.CP2_DEVICE_ACCOUNT_DETECTION_ENABLED)) { 57 return new Cp2DeviceLocalAccountLocator(context.getContentResolver(), 58 ObjectFactory.getDeviceLocalAccountTypeFactory(context), knownAccountTypes); 59 } 60 return NULL_ONLY; 61 } 62 create(Context context)63 public static DeviceLocalAccountLocator create(Context context) { 64 final AccountManager accountManager = 65 (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE); 66 final Set<String> knownTypes = new HashSet<>(); 67 for (Account account : accountManager.getAccounts()) { 68 knownTypes.add(account.type); 69 } 70 if (Flags.getInstance().getBoolean(Experiments.CP2_DEVICE_ACCOUNT_DETECTION_ENABLED)) { 71 return new Cp2DeviceLocalAccountLocator(context.getContentResolver(), 72 ObjectFactory.getDeviceLocalAccountTypeFactory(context), knownTypes); 73 } else { 74 return new NexusDeviceAccountLocator(context, accountManager); 75 } 76 } 77 78 /** 79 * On Nexus the "device" account uses "null" values for the account name and type columns 80 * 81 * <p>However, the focus sync adapter migrates contacts from this null account to a Google 82 * account if one exists. Hence, the device account should be returned only when there is no 83 * Google Account added or when there already exists contacts in the null account. 84 * </p> 85 */ 86 public static class NexusDeviceAccountLocator extends DeviceLocalAccountLocator { 87 private final Context mContext; 88 private final AccountManager mAccountManager; 89 90 NexusDeviceAccountLocator(Context context, AccountManager accountManager)91 public NexusDeviceAccountLocator(Context context, AccountManager accountManager) { 92 mContext = context; 93 mAccountManager = accountManager; 94 } 95 96 @Override getDeviceLocalAccounts()97 public List<AccountWithDataSet> getDeviceLocalAccounts() { 98 @SuppressWarnings("MissingPermission") 99 final Account[] accounts = mAccountManager 100 .getAccountsByType(GoogleAccountType.ACCOUNT_TYPE); 101 102 if (accounts.length > 0 && !AccountWithDataSet.getNullAccount().hasData(mContext)) { 103 return Collections.emptyList(); 104 } else { 105 return Collections.singletonList(AccountWithDataSet.getNullAccount()); 106 } 107 } 108 } 109 } 110