• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 package com.android.contacts.util;
18 
19 import android.accounts.Account;
20 import android.app.Activity;
21 import android.app.Fragment;
22 import android.content.ActivityNotFoundException;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.IntentFilter;
26 import android.graphics.drawable.Drawable;
27 import android.provider.ContactsContract.Contacts;
28 import android.provider.ContactsContract.Intents;
29 import android.text.TextUtils;
30 import android.util.Log;
31 import android.widget.Toast;
32 
33 import com.android.contacts.R;
34 import com.android.contacts.activities.ContactEditorActivity;
35 import com.android.contacts.list.AccountFilterActivity;
36 import com.android.contacts.list.ContactListFilter;
37 import com.android.contacts.list.ContactListFilterController;
38 import com.android.contacts.model.AccountTypeManager;
39 import com.android.contacts.model.account.AccountInfo;
40 import com.android.contacts.model.account.AccountType;
41 import com.android.contacts.model.account.AccountWithDataSet;
42 import com.android.contacts.preference.ContactsPreferences;
43 import com.android.contacts.util.concurrent.ContactsExecutors;
44 import com.android.contacts.util.concurrent.ListenableFutureLoader;
45 import com.android.contactsbind.ObjectFactory;
46 
47 import com.google.common.base.Function;
48 import com.google.common.util.concurrent.Futures;
49 import com.google.common.util.concurrent.ListenableFuture;
50 
51 import java.util.ArrayList;
52 import java.util.List;
53 
54 /**
55  * Utility class for account filter manipulation.
56  */
57 public class AccountFilterUtil {
58     private static final String TAG = AccountFilterUtil.class.getSimpleName();
59 
60      /**
61       * Launches account filter setting Activity using
62       * {@link Fragment#startActivityForResult(Intent, int)}.
63       *
64       * @param requestCode requestCode for {@link Activity#startActivityForResult(Intent, int)}
65       * @param currentFilter currently-selected filter, so that it can be displayed as activated.
66       */
startAccountFilterActivityForResult( Fragment fragment, int requestCode, ContactListFilter currentFilter)67      public static void startAccountFilterActivityForResult(
68              Fragment fragment, int requestCode, ContactListFilter currentFilter) {
69          final Activity activity = fragment.getActivity();
70          if (activity != null) {
71              final Intent intent = new Intent(activity, AccountFilterActivity.class);
72              fragment.startActivityForResult(intent, requestCode);
73          } else {
74              Log.w(TAG, "getActivity() returned null. Ignored");
75          }
76      }
77 
78     /**
79      * Useful method to handle onActivityResult() for
80      * {@link #startAccountFilterActivityForResult(Fragment, int, ContactListFilter)}.
81      *
82      * This will update filter via a given ContactListFilterController.
83      */
handleAccountFilterResult( ContactListFilterController filterController, int resultCode, Intent data)84     public static void handleAccountFilterResult(
85             ContactListFilterController filterController, int resultCode, Intent data) {
86         if (resultCode == Activity.RESULT_OK) {
87             final ContactListFilter filter = (ContactListFilter)
88                     data.getParcelableExtra(AccountFilterActivity.EXTRA_CONTACT_LIST_FILTER);
89             if (filter == null) {
90                 return;
91             }
92             if (filter.filterType == ContactListFilter.FILTER_TYPE_CUSTOM) {
93                 filterController.selectCustomFilter();
94             } else {
95                 filterController.setContactListFilter(filter, /* persistent */
96                         filter.filterType == ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS);
97             }
98         }
99     }
100 
101     /**
102      * Loads a list of contact list filters
103      */
104     public static class FilterLoader extends ListenableFutureLoader<List<ContactListFilter>> {
105         private AccountTypeManager mAccountTypeManager;
106         private DeviceLocalAccountTypeFactory mDeviceLocalFactory;
107 
FilterLoader(Context context)108         public FilterLoader(Context context) {
109             super(context, new IntentFilter(AccountTypeManager.BROADCAST_ACCOUNTS_CHANGED));
110             mAccountTypeManager = AccountTypeManager.getInstance(context);
111             mDeviceLocalFactory = ObjectFactory.getDeviceLocalAccountTypeFactory(context);
112         }
113 
114 
115         @Override
loadData()116         protected ListenableFuture<List<ContactListFilter>> loadData() {
117             return Futures.transform(mAccountTypeManager.filterAccountsAsync(
118                     AccountTypeManager.drawerDisplayableFilter()),
119                     new Function<List<AccountInfo>, List<ContactListFilter>>() {
120                         @Override
121                         public List<ContactListFilter> apply(List<AccountInfo> input) {
122                             return getFiltersForAccounts(input);
123                         }
124                     }, ContactsExecutors.getDefaultThreadPoolExecutor());
125         }
126 
getFiltersForAccounts(List<AccountInfo> accounts)127         private List<ContactListFilter> getFiltersForAccounts(List<AccountInfo> accounts) {
128             final ArrayList<ContactListFilter> accountFilters = new ArrayList<>();
129             AccountInfo.sortAccounts(getDefaultAccount(getContext()), accounts);
130 
131             for (AccountInfo accountInfo : accounts) {
132                 final AccountType accountType = accountInfo.getType();
133                 final AccountWithDataSet account = accountInfo.getAccount();
134                 if ((accountType.isExtension() ||
135                         DeviceLocalAccountTypeFactory.Util.isLocalAccountType(
136                                 mDeviceLocalFactory, account.type)) &&
137                         !account.hasData(getContext())) {
138                     // Hide extensions and device accounts with no raw_contacts.
139                     continue;
140                 }
141                 final Drawable icon = accountType != null ?
142                         accountType.getDisplayIcon(getContext()) : null;
143                 if (mDeviceLocalFactory.classifyAccount(account.type)
144                         == DeviceLocalAccountTypeFactory.TYPE_DEVICE) {
145                     accountFilters.add(ContactListFilter.createDeviceContactsFilter(icon, account));
146                 } else if (mDeviceLocalFactory.classifyAccount(account.type)
147                         == DeviceLocalAccountTypeFactory.TYPE_SIM) {
148                     accountFilters.add(ContactListFilter.createSimContactsFilter(icon, account));
149                 } else {
150                     accountFilters.add(ContactListFilter.createAccountFilter(
151                             account.type, account.name, account.dataSet, icon));
152                 }
153             }
154 
155             return accountFilters;
156         }
157     }
158 
159     private static AccountWithDataSet getDefaultAccount(Context context) {
160         return new ContactsPreferences(context).getDefaultAccount();
161     }
162 
163     /**
164      * Returns a {@link ContactListFilter} of type
165      * {@link ContactListFilter#FILTER_TYPE_ALL_ACCOUNTS}, or if a custom "Contacts to display"
166      * filter has been set, then one of type {@link ContactListFilter#FILTER_TYPE_CUSTOM}.
167      */
168     public static ContactListFilter createContactsFilter(Context context) {
169         final int filterType =
170                 ContactListFilterController.getInstance(context).isCustomFilterPersisted()
171                         ? ContactListFilter.FILTER_TYPE_CUSTOM
172                         : ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS;
173         return ContactListFilter.createFilterWithType(filterType);
174     }
175 
176     /**
177      * Start editor intent; and if filter is an account filter, we pass account info to editor so
178      * as to create a contact in that account.
179      */
180     public static void startEditorIntent(Context context, Intent src, ContactListFilter filter) {
181         final Intent intent = new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI);
182         intent.putExtras(src);
183 
184         // If we are in account view, we pass the account explicitly in order to
185         // create contact in the account. This will prevent the default account dialog
186         // from being displayed.
187         if (!isAllContactsFilter(filter) && filter.accountName != null
188                 && filter.accountType != null) {
189             final Account account = new Account(filter.accountName, filter.accountType);
190             intent.putExtra(Intents.Insert.EXTRA_ACCOUNT, account);
191             intent.putExtra(Intents.Insert.EXTRA_DATA_SET, filter.dataSet);
192         } else if (isDeviceContactsFilter(filter)) {
193             intent.putExtra(ContactEditorActivity.EXTRA_ACCOUNT_WITH_DATA_SET,
194                     filter.toAccountWithDataSet());
195         }
196 
197         try {
198             ImplicitIntentsUtil.startActivityInApp(context, intent);
199         } catch (ActivityNotFoundException ex) {
200             Toast.makeText(context, R.string.missing_app, Toast.LENGTH_SHORT).show();
201         }
202     }
203 
204     public static boolean isAllContactsFilter(ContactListFilter filter) {
205         return filter != null && filter.isContactsFilterType();
206     }
207 
208     public static boolean isDeviceContactsFilter(ContactListFilter filter) {
209         return filter.filterType == ContactListFilter.FILTER_TYPE_DEVICE_CONTACTS;
210     }
211 
212     /**
213      * Returns action bar title for filter and returns default title "Contacts" if filter is empty.
214      */
215     public static String getActionBarTitleForFilter(Context context, ContactListFilter filter) {
216         if (filter.filterType == ContactListFilter.FILTER_TYPE_DEVICE_CONTACTS) {
217             return context.getString(R.string.account_phone);
218         } else if (filter.filterType == ContactListFilter.FILTER_TYPE_SIM_CONTACTS) {
219             return context.getString(R.string.account_sim);
220         } else if (filter.filterType == ContactListFilter.FILTER_TYPE_ACCOUNT &&
221                 !TextUtils.isEmpty(filter.accountName)) {
222             return getActionBarTitleForAccount(context, filter);
223         }
224         return context.getString(R.string.contactsList);
225     }
226 
227     private static String getActionBarTitleForAccount(Context context, ContactListFilter filter) {
228         final AccountInfo info = AccountTypeManager.getInstance(context)
229                 .getAccountInfoForAccount(filter.toAccountWithDataSet());
230         if (info == null) {
231             return context.getString(R.string.contactsList);
232         }
233 
234         if (info.hasGoogleAccountType()) {
235             return context.getString(R.string.title_from_google);
236         }
237         return context.getString(R.string.title_from_other_accounts,
238                 info.getNameLabel().toString());
239     }
240 }
241