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