blob: 96c5113f75d7a4e70cdf793d5df8dc680cfdc798 [file] [log] [blame]
Chiao Chengbeca8562012-11-28 18:06:44 -08001/*
2 * Copyright (C) 2012 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
17package com.android.contacts.common.util;
18
Wenyi Wang79675452016-08-17 10:43:28 -070019import android.accounts.Account;
Chiao Chengbeca8562012-11-28 18:06:44 -080020import android.app.Activity;
Walter Jangf2cad222016-07-14 19:49:06 +000021import android.app.Fragment;
Wenyi Wang79675452016-08-17 10:43:28 -070022import android.content.ActivityNotFoundException;
Wenyi Wangb3186762016-04-17 17:29:31 -070023import android.content.AsyncTaskLoader;
Chiao Chengbeca8562012-11-28 18:06:44 -080024import android.content.Context;
25import android.content.Intent;
Wenyi Wangb3186762016-04-17 17:29:31 -070026import android.graphics.drawable.Drawable;
Wenyi Wang79675452016-08-17 10:43:28 -070027import android.provider.ContactsContract.Contacts;
28import android.provider.ContactsContract.Intents;
Wenyi Wangcfe94652016-10-03 21:05:04 -070029import android.text.TextUtils;
Chiao Chengbeca8562012-11-28 18:06:44 -080030import android.util.Log;
Wenyi Wang79675452016-08-17 10:43:28 -070031import android.widget.Toast;
Chiao Chengbeca8562012-11-28 18:06:44 -080032
Wenyi Wang79675452016-08-17 10:43:28 -070033import com.android.contacts.R;
Gary Mai363af602016-09-28 10:01:23 -070034import com.android.contacts.activities.ContactEditorActivity;
Walter Jangf2cad222016-07-14 19:49:06 +000035import com.android.contacts.common.list.AccountFilterActivity;
Chiao Chengbeca8562012-11-28 18:06:44 -080036import com.android.contacts.common.list.ContactListFilter;
37import com.android.contacts.common.list.ContactListFilterController;
Wenyi Wangb3186762016-04-17 17:29:31 -070038import com.android.contacts.common.model.AccountTypeManager;
Wenyi Wangcfe94652016-10-03 21:05:04 -070039import com.android.contacts.common.model.account.AccountDisplayInfo;
40import com.android.contacts.common.model.account.AccountDisplayInfoFactory;
Wenyi Wangb3186762016-04-17 17:29:31 -070041import com.android.contacts.common.model.account.AccountType;
42import com.android.contacts.common.model.account.AccountWithDataSet;
Marcus Hagerott949d4e82016-09-20 13:23:05 -070043import com.android.contacts.common.preference.ContactsPreferences;
Marcus Hagerottbc510842016-09-09 19:29:45 -070044import com.android.contactsbind.ObjectFactory;
Gary Maiac333592016-09-28 17:27:40 -070045
Wenyi Wangb3186762016-04-17 17:29:31 -070046import com.google.common.collect.Lists;
47
48import java.util.ArrayList;
49import java.util.List;
Chiao Chengbeca8562012-11-28 18:06:44 -080050
51/**
52 * Utility class for account filter manipulation.
53 */
54public class AccountFilterUtil {
55 private static final String TAG = AccountFilterUtil.class.getSimpleName();
56
Walter Jangf2cad222016-07-14 19:49:06 +000057 /**
58 * Launches account filter setting Activity using
59 * {@link Fragment#startActivityForResult(Intent, int)}.
60 *
61 * @param requestCode requestCode for {@link Activity#startActivityForResult(Intent, int)}
62 * @param currentFilter currently-selected filter, so that it can be displayed as activated.
63 */
64 public static void startAccountFilterActivityForResult(
65 Fragment fragment, int requestCode, ContactListFilter currentFilter) {
66 final Activity activity = fragment.getActivity();
67 if (activity != null) {
68 final Intent intent = new Intent(activity, AccountFilterActivity.class);
69 fragment.startActivityForResult(intent, requestCode);
70 } else {
71 Log.w(TAG, "getActivity() returned null. Ignored");
72 }
73 }
Wenyi Wang1aa9d9f2016-04-22 16:31:51 -070074
Chiao Chengbeca8562012-11-28 18:06:44 -080075 /**
Walter Jangf2cad222016-07-14 19:49:06 +000076 * Useful method to handle onActivityResult() for
77 * {@link #startAccountFilterActivityForResult(Fragment, int, ContactListFilter)}.
78 *
Chiao Chengbeca8562012-11-28 18:06:44 -080079 * This will update filter via a given ContactListFilterController.
80 */
81 public static void handleAccountFilterResult(
82 ContactListFilterController filterController, int resultCode, Intent data) {
83 if (resultCode == Activity.RESULT_OK) {
84 final ContactListFilter filter = (ContactListFilter)
Walter Jangf2cad222016-07-14 19:49:06 +000085 data.getParcelableExtra(AccountFilterActivity.EXTRA_CONTACT_LIST_FILTER);
Chiao Chengbeca8562012-11-28 18:06:44 -080086 if (filter == null) {
87 return;
88 }
89 if (filter.filterType == ContactListFilter.FILTER_TYPE_CUSTOM) {
90 filterController.selectCustomFilter();
91 } else {
Wenyi Wang1cfe9c62016-06-01 20:49:13 -070092 filterController.setContactListFilter(filter, /* persistent */
93 filter.filterType == ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS);
Chiao Chengbeca8562012-11-28 18:06:44 -080094 }
95 }
96 }
Wenyi Wangb3186762016-04-17 17:29:31 -070097
98 /**
99 * Loads a list of contact list filters
100 */
101 public static class FilterLoader extends AsyncTaskLoader<List<ContactListFilter>> {
102 private Context mContext;
Marcus Hagerottbc510842016-09-09 19:29:45 -0700103 private DeviceLocalAccountTypeFactory mDeviceLocalFactory;
Wenyi Wangb3186762016-04-17 17:29:31 -0700104
105 public FilterLoader(Context context) {
106 super(context);
107 mContext = context;
Marcus Hagerottbc510842016-09-09 19:29:45 -0700108 mDeviceLocalFactory = ObjectFactory.getDeviceLocalAccountTypeFactory(context);
Wenyi Wangb3186762016-04-17 17:29:31 -0700109 }
110
111 @Override
112 public List<ContactListFilter> loadInBackground() {
Marcus Hagerottbc510842016-09-09 19:29:45 -0700113 return loadAccountFilters(mContext, mDeviceLocalFactory);
Wenyi Wangb3186762016-04-17 17:29:31 -0700114 }
115
116 @Override
117 protected void onStartLoading() {
118 forceLoad();
119 }
120
121 @Override
122 protected void onStopLoading() {
123 cancelLoad();
124 }
125
126 @Override
127 protected void onReset() {
128 onStopLoading();
129 }
130 }
131
Marcus Hagerottbc510842016-09-09 19:29:45 -0700132 private static List<ContactListFilter> loadAccountFilters(Context context,
133 DeviceLocalAccountTypeFactory deviceAccountTypeFactory) {
Wenyi Wangb3186762016-04-17 17:29:31 -0700134 final ArrayList<ContactListFilter> accountFilters = Lists.newArrayList();
135 final AccountTypeManager accountTypeManager = AccountTypeManager.getInstance(context);
Gary Maiac333592016-09-28 17:27:40 -0700136 final List<AccountWithDataSet> accounts = accountTypeManager.getSortedAccounts(
137 /* defaultAccount */ getDefaultAccount(context), /* contactWritableOnly */ true);
Tingting Wang0ac73ba2016-07-05 22:33:01 -0700138
Wenyi Wangb3186762016-04-17 17:29:31 -0700139 for (AccountWithDataSet account : accounts) {
140 final AccountType accountType =
141 accountTypeManager.getAccountType(account.type, account.dataSet);
Marcus Hagerottbc510842016-09-09 19:29:45 -0700142 if ((accountType.isExtension() || DeviceLocalAccountTypeFactory.Util.isLocalAccountType(
143 deviceAccountTypeFactory, account.type)) && !account.hasData(context)) {
144 // Hide extensions and device accounts with no raw_contacts.
Wenyi Wangb3186762016-04-17 17:29:31 -0700145 continue;
146 }
147 final Drawable icon = accountType != null ? accountType.getDisplayIcon(context) : null;
Marcus Hagerottbc510842016-09-09 19:29:45 -0700148 if (DeviceLocalAccountTypeFactory.Util.isLocalAccountType(
149 deviceAccountTypeFactory, account.type)) {
150 accountFilters.add(ContactListFilter.createDeviceContactsFilter(icon, account));
Tingting Wang0ac73ba2016-07-05 22:33:01 -0700151 } else {
152 accountFilters.add(ContactListFilter.createAccountFilter(
153 account.type, account.name, account.dataSet, icon));
154 }
Wenyi Wangb3186762016-04-17 17:29:31 -0700155 }
Tingting Wang0ac73ba2016-07-05 22:33:01 -0700156
Wenyi Wangb3186762016-04-17 17:29:31 -0700157 final ArrayList<ContactListFilter> result = Lists.newArrayList();
158 result.addAll(accountFilters);
159 return result;
160 }
Wenyi Wangaa0e6ff2016-07-06 17:22:42 -0700161
162 private static AccountWithDataSet getDefaultAccount(Context context) {
Marcus Hagerott949d4e82016-09-20 13:23:05 -0700163 return new ContactsPreferences(context).getDefaultAccount();
Wenyi Wangaa0e6ff2016-07-06 17:22:42 -0700164 }
Wenyi Wang587b8f22016-08-17 17:40:45 -0700165
166 /**
167 * Returns a {@link ContactListFilter} of type
168 * {@link ContactListFilter#FILTER_TYPE_ALL_ACCOUNTS}, or if a custom "Contacts to display"
169 * filter has been set, then one of type {@link ContactListFilter#FILTER_TYPE_CUSTOM}.
170 */
171 public static ContactListFilter createContactsFilter(Context context) {
172 final int filterType =
173 ContactListFilterController.getInstance(context).isCustomFilterPersisted()
174 ? ContactListFilter.FILTER_TYPE_CUSTOM
175 : ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS;
176 return ContactListFilter.createFilterWithType(filterType);
177 }
Wenyi Wang79675452016-08-17 10:43:28 -0700178
179 /**
180 * Start editor intent; and if filter is an account filter, we pass account info to editor so
181 * as to create a contact in that account.
182 */
183 public static void startEditorIntent(Context context, Intent src, ContactListFilter filter) {
184 final Intent intent = new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI);
185 intent.putExtras(src);
186
187 // If we are in account view, we pass the account explicitly in order to
188 // create contact in the account. This will prevent the default account dialog
189 // from being displayed.
Marcus Hagerott935b56a2016-09-07 11:59:35 -0700190 if (!isAllContactsFilter(filter) && filter.accountName != null
191 && filter.accountType != null) {
Wenyi Wang79675452016-08-17 10:43:28 -0700192 final Account account = new Account(filter.accountName, filter.accountType);
193 intent.putExtra(Intents.Insert.EXTRA_ACCOUNT, account);
194 intent.putExtra(Intents.Insert.EXTRA_DATA_SET, filter.dataSet);
Marcus Hagerott935b56a2016-09-07 11:59:35 -0700195 } else if (isDeviceContactsFilter(filter)) {
196 // It's OK to add this even though it's an implicit intent. If a different app
197 // receives the intent it should just ignore the flag.
Gary Mai363af602016-09-28 10:01:23 -0700198 intent.putExtra(ContactEditorActivity.EXTRA_SAVE_TO_DEVICE_FLAG, true);
Wenyi Wang79675452016-08-17 10:43:28 -0700199 }
200
201 try {
202 ImplicitIntentsUtil.startActivityInApp(context, intent);
203 } catch (ActivityNotFoundException ex) {
204 Toast.makeText(context, R.string.missing_app, Toast.LENGTH_SHORT).show();
205 }
206 }
207
208 public static boolean isAllContactsFilter(ContactListFilter filter) {
209 return filter != null && filter.isContactsFilterType();
210 }
211
212 public static boolean isDeviceContactsFilter(ContactListFilter filter) {
213 return filter.filterType == ContactListFilter.FILTER_TYPE_DEVICE_CONTACTS;
214 }
Wenyi Wangcfe94652016-10-03 21:05:04 -0700215
216 /**
217 * Returns action bar title for filter and returns default title "Contacts" if filter is empty.
218 */
219 public static String getActionBarTitleForFilter(Context context, ContactListFilter filter) {
220 if (filter.filterType == ContactListFilter.FILTER_TYPE_DEVICE_CONTACTS) {
221 return context.getString(R.string.account_phone);
Marcus Hagerottf7451132016-10-20 14:32:16 -0700222 } else if (filter.filterType == ContactListFilter.FILTER_TYPE_ACCOUNT &&
223 !TextUtils.isEmpty(filter.accountName)) {
Wenyi Wangcfe94652016-10-03 21:05:04 -0700224 return getActionBarTitleForAccount(context, filter);
225 }
226 return context.getString(R.string.contactsList);
227 }
228
229 private static String getActionBarTitleForAccount(Context context, ContactListFilter filter) {
230 final AccountDisplayInfoFactory factory =
231 AccountDisplayInfoFactory.forAllAccounts(context);
232 final AccountDisplayInfo account = factory.getAccountDisplayInfoFor(filter);
233 if (account.hasGoogleAccountType()) {
234 return context.getString(R.string.title_from_google);
235 }
236 return account.withFormattedName(context, R.string.title_from_other_accounts)
237 .getNameLabel().toString();
238 }
Chiao Chengbeca8562012-11-28 18:06:44 -0800239}