Home | History | Annotate | Download | only in contacts
      1 /*
      2  * Copyright (C) 2006 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;
     18 
     19 import com.android.contacts.model.ContactsSource;
     20 import com.android.contacts.model.Sources;
     21 
     22 import android.content.Context;
     23 import android.content.pm.PackageManager;
     24 import android.database.Cursor;
     25 import android.graphics.Bitmap;
     26 import android.graphics.drawable.Drawable;
     27 import android.net.Uri;
     28 import android.provider.ContactsContract.RawContacts;
     29 import android.provider.ContactsContract.CommonDataKinds.Email;
     30 import android.provider.ContactsContract.CommonDataKinds.Nickname;
     31 import android.provider.ContactsContract.CommonDataKinds.Phone;
     32 import android.provider.ContactsContract.CommonDataKinds.StructuredName;
     33 import android.provider.ContactsContract.Contacts.Data;
     34 import android.util.Log;
     35 import android.view.LayoutInflater;
     36 import android.view.View;
     37 import android.view.ViewGroup;
     38 import android.widget.AdapterView;
     39 import android.widget.ArrayAdapter;
     40 import android.widget.ImageView;
     41 import android.widget.ListView;
     42 import android.widget.TextView;
     43 
     44 import java.util.ArrayList;
     45 import java.util.Collections;
     46 import java.util.HashMap;
     47 import java.util.List;
     48 
     49 /**
     50  * A list view for constituent contacts of an aggregate.  Shows the contact name, source icon
     51  * and additional data such as a nickname, email address or phone number, whichever
     52  * is available.
     53  */
     54 public class SplitAggregateView extends ListView {
     55 
     56     private static final String TAG = "SplitAggregateView";
     57 
     58     private interface SplitQuery {
     59         String[] COLUMNS = new String[] {
     60                 Data.MIMETYPE, RawContacts.ACCOUNT_TYPE, Data.RAW_CONTACT_ID, Data.IS_PRIMARY,
     61                 StructuredName.DISPLAY_NAME, Nickname.NAME, Email.DATA, Phone.NUMBER
     62         };
     63 
     64         int MIMETYPE = 0;
     65         int ACCOUNT_TYPE = 1;
     66         int RAW_CONTACT_ID = 2;
     67         int IS_PRIMARY = 3;
     68         int DISPLAY_NAME = 4;
     69         int NICKNAME = 5;
     70         int EMAIL = 6;
     71         int PHONE = 7;
     72     }
     73 
     74     private final Uri mAggregateUri;
     75     private OnContactSelectedListener mListener;
     76     private Sources mSources;
     77 
     78     /**
     79      * Listener interface that gets the contact ID of the user-selected contact.
     80      */
     81     public interface OnContactSelectedListener {
     82         void onContactSelected(long rawContactId);
     83     }
     84 
     85     /**
     86      * Constructor.
     87      */
     88     public SplitAggregateView(Context context, Uri aggregateUri) {
     89         super(context);
     90 
     91         mAggregateUri = aggregateUri;
     92 
     93         mSources = Sources.getInstance(context);
     94 
     95         final List<RawContactInfo> list = loadData();
     96 
     97         setAdapter(new SplitAggregateAdapter(context, list));
     98         setOnItemClickListener(new OnItemClickListener() {
     99 
    100             public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
    101                 mListener.onContactSelected(list.get(position).rawContactId);
    102             }
    103         });
    104     }
    105 
    106     /**
    107      * Sets a contact selection listener.
    108      */
    109     public void setOnContactSelectedListener(OnContactSelectedListener listener) {
    110         mListener = listener;
    111     }
    112 
    113     /**
    114      * Contact information loaded from the content provider.
    115      */
    116     private static class RawContactInfo implements Comparable<RawContactInfo> {
    117         final long rawContactId;
    118         String accountType;
    119         String name;
    120         String phone;
    121         String email;
    122         String nickname;
    123 
    124         public RawContactInfo(long rawContactId) {
    125             this.rawContactId = rawContactId;
    126         }
    127 
    128         public String getAdditionalData() {
    129             if (nickname != null) {
    130                 return nickname;
    131             }
    132 
    133             if (email != null) {
    134                 return email;
    135             }
    136 
    137             if (phone != null) {
    138                 return phone;
    139             }
    140 
    141             return "";
    142         }
    143 
    144         public int compareTo(RawContactInfo another) {
    145             String thisAccount = accountType != null ? accountType : "";
    146             String thatAccount = another.accountType != null ? another.accountType : "";
    147             return thisAccount.compareTo(thatAccount);
    148         }
    149     }
    150 
    151     /**
    152      * Loads data from the content provider, organizes it into {@link RawContactInfo} objects
    153      * and returns a sorted list of {@link RawContactInfo}'s.
    154      */
    155     private List<RawContactInfo> loadData() {
    156         HashMap<Long, RawContactInfo> rawContactInfos = new HashMap<Long, RawContactInfo>();
    157         Uri dataUri = Uri.withAppendedPath(mAggregateUri, Data.CONTENT_DIRECTORY);
    158         Cursor cursor = getContext().getContentResolver().query(dataUri,
    159                 SplitQuery.COLUMNS, null, null, null);
    160         try {
    161             while (cursor.moveToNext()) {
    162                 long rawContactId = cursor.getLong(SplitQuery.RAW_CONTACT_ID);
    163                 RawContactInfo info = rawContactInfos.get(rawContactId);
    164                 if (info == null) {
    165                     info = new RawContactInfo(rawContactId);
    166                     rawContactInfos.put(rawContactId, info);
    167                     info.accountType = cursor.getString(SplitQuery.ACCOUNT_TYPE);
    168                 }
    169 
    170                 String mimetype = cursor.getString(SplitQuery.MIMETYPE);
    171                 if (StructuredName.CONTENT_ITEM_TYPE.equals(mimetype)) {
    172                     loadStructuredName(cursor, info);
    173                 } else if (Phone.CONTENT_ITEM_TYPE.equals(mimetype)) {
    174                     loadPhoneNumber(cursor, info);
    175                 } else if (Email.CONTENT_ITEM_TYPE.equals(mimetype)) {
    176                     loadEmail(cursor, info);
    177                 } else if (Nickname.CONTENT_ITEM_TYPE.equals(mimetype)) {
    178                     loadNickname(cursor, info);
    179                 }
    180             }
    181         } finally {
    182             cursor.close();
    183         }
    184 
    185         List<RawContactInfo> list = new ArrayList<RawContactInfo>(rawContactInfos.values());
    186         Collections.sort(list);
    187         return list;
    188     }
    189 
    190     private void loadStructuredName(Cursor cursor, RawContactInfo info) {
    191         info.name = cursor.getString(SplitQuery.DISPLAY_NAME);
    192     }
    193 
    194     private void loadNickname(Cursor cursor, RawContactInfo info) {
    195         if (info.nickname == null || cursor.getInt(SplitQuery.IS_PRIMARY) != 0) {
    196             info.nickname = cursor.getString(SplitQuery.NICKNAME);
    197         }
    198     }
    199 
    200     private void loadEmail(Cursor cursor, RawContactInfo info) {
    201         if (info.email == null || cursor.getInt(SplitQuery.IS_PRIMARY) != 0) {
    202             info.email = cursor.getString(SplitQuery.EMAIL);
    203         }
    204     }
    205 
    206     private void loadPhoneNumber(Cursor cursor, RawContactInfo info) {
    207         if (info.phone == null || cursor.getInt(SplitQuery.IS_PRIMARY) != 0) {
    208             info.phone = cursor.getString(SplitQuery.PHONE);
    209         }
    210     }
    211 
    212     private static class SplitAggregateItemCache  {
    213         TextView name;
    214         TextView additionalData;
    215         ImageView sourceIcon;
    216     }
    217 
    218     /**
    219      * List adapter for the list of {@link RawContactInfo} objects.
    220      */
    221     private class SplitAggregateAdapter extends ArrayAdapter<RawContactInfo> {
    222 
    223         private LayoutInflater mInflater;
    224 
    225         public SplitAggregateAdapter(Context context, List<RawContactInfo> sources) {
    226             super(context, 0, sources);
    227             mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    228         }
    229 
    230         @Override
    231         public View getView(int position, View convertView, ViewGroup parent) {
    232             if (convertView == null) {
    233                 convertView = mInflater.inflate(R.layout.split_aggregate_list_item, parent, false);
    234             }
    235 
    236             SplitAggregateItemCache cache = (SplitAggregateItemCache)convertView.getTag();
    237             if (cache == null) {
    238                 cache = new SplitAggregateItemCache();
    239                 cache.name = (TextView)convertView.findViewById(R.id.name);
    240                 cache.additionalData = (TextView)convertView.findViewById(R.id.additionalData);
    241                 cache.sourceIcon = (ImageView)convertView.findViewById(R.id.sourceIcon);
    242                 convertView.setTag(cache);
    243             }
    244 
    245             final RawContactInfo info = getItem(position);
    246             cache.name.setText(info.name);
    247             cache.additionalData.setText(info.getAdditionalData());
    248 
    249             Drawable icon = null;
    250             ContactsSource source = mSources.getInflatedSource(info.accountType,
    251                     ContactsSource.LEVEL_SUMMARY);
    252             if (source != null) {
    253                 icon = source.getDisplayIcon(getContext());
    254             }
    255             if (icon != null) {
    256                 cache.sourceIcon.setImageDrawable(icon);
    257             } else {
    258                 cache.sourceIcon.setImageResource(R.drawable.unknown_source);
    259             }
    260             return convertView;
    261         }
    262     }
    263 }
    264