package com.android.contacts; import com.android.contacts.util.Config; import com.android.internal.telephony.CallerInfo; import com.android.internal.telephony.PhoneFactory; import android.accounts.Account; import android.content.ContentUris; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Color; import android.net.Uri; import android.provider.CallLog; import android.provider.ContactsContract; import android.telephony.PhoneNumberUtils; import android.telephony.TelephonyManager; import android.text.Html; import android.text.SpannableString; import android.text.Spanned; import android.text.TextUtils; import android.text.style.ForegroundColorSpan; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.TextView; import java.io.InputStream; import java.util.ArrayList; public class ContactAdapter extends BaseAdapter { private static final String TAG = "ContactAdapter"; public static final int RESUME = 0; public static final int PAUSE = 1; public static final int STOP = 2; public static final int CLEAR = 3; private ContactPhotoLoader mPhotoLoader; private Context context; /** * the final list of contact & call log that be shown */ private ArrayList<ContactEntity> mList = new ArrayList<ContactEntity>(); LayoutInflater mInflater; /** * search string */ private String mSearchStr = ""; // make click reflection a little faster End /** * NUMBER_ALPHABETS[0]:2('a','b','c'),... */ private final char[][] NUMBER_ALPHABETS = { { 'a', 'b', 'c' }, { 'd', 'e', 'f' }, { 'g', 'h', 'i' }, { 'j', 'k', 'l' }, { 'm', 'n', 'o' }, { 'p', 'q', 'r', 's' }, { 't', 'u', 'v' }, { 'w', 'x', 'y', 'z' } }; public ContactAdapter(Context context, ArrayList<ContactEntity> clist) { this.context = context; mInflater = LayoutInflater.from(context); mPhotoLoader = new ContactPhotoLoader(context, R.drawable.ic_contact_list_picture); setList(clist); } public int getCount() { return mList.size(); } public ContactEntity getItem(int position) { return mList.get(position); } public long getItemId(int position) { return position; } // make click reflection a little faster Start class ViewHolder { ImageView contactPhoto; TextView contactName; TextView contactNumber; } public View getView(int position, View convertView, ViewGroup parent) { Log.d(TAG, "getView"); ViewHolder holder = null; if (convertView == null && mInflater != null) { convertView = mInflater.inflate(R.layout.dialer_contacts_item, parent, false); holder = new ViewHolder(); holder.contactPhoto = (ImageView) convertView.findViewById(R.id.photo); holder.contactName = (TextView) convertView.findViewById(R.id.contactName); holder.contactNumber = (TextView) convertView.findViewById(R.id.contactNumber); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } final ContactEntity ce = getItem(position); int photoId = 0; String accountName = ce.getAccountName(); String simIndex = ce.getSimIndex(); if (0 != ce.getCallLogType()) { switch (ce.getCallLogType()) { //bond mod 20120710 begin /* case CallLog.Calls.INCOMING_TYPE: photoId = R.drawable.ic_call_log_list_incoming_call; break; case CallLog.Calls.OUTGOING_TYPE: photoId = R.drawable.ic_call_log_list_outgoing_call; break; case CallLog.Calls.MISSED_TYPE: photoId = R.drawable.ic_call_log_list_missed_call; break; default: break; */ case CallLog.Calls.INCOMING_TYPE: photoId = R.drawable.ic_dialer_header_incoming_call; break; case CallLog.Calls.OUTGOING_TYPE: photoId = R.drawable.ic_dialer_header_outgoing_call; break; case CallLog.Calls.MISSED_TYPE: photoId = R.drawable.ic_dialer_header_missed_call; break; default: break; //bond mod 20120710 end } holder.contactPhoto.setImageResource(photoId); } else if (!TextUtils.isEmpty(ce.getPhotoId())) { try { photoId = Integer.parseInt(ce.getPhotoId()); } catch (NumberFormatException e) { photoId = 0; } mPhotoLoader.loadPhoto(holder.contactPhoto, photoId); } else if (Account.SIM1_ACCOUNT_NAME.equals(accountName)) { photoId = R.drawable.ic_menu_add_sim1; mPhotoLoader.loadPhoto(holder.contactPhoto, photoId); } else if (Account.SIM2_ACCOUNT_NAME.equals(accountName)) { photoId = R.drawable.ic_menu_add_sim2; mPhotoLoader.loadPhoto(holder.contactPhoto, photoId); } else { if(!"0".equals(simIndex)){ photoId = R.drawable.ic_sim_contact_list_picture; mPhotoLoader.loadPhoto(holder.contactPhoto, photoId); } else { mPhotoLoader.loadPhoto(holder.contactPhoto, 0); } } holder.contactNumber.setVisibility(View.VISIBLE); if (ce.getPhoneNumber() != null) { TelephonyManager tm1 = (TelephonyManager) context.getSystemService(PhoneFactory .getServiceName(Context.TELEPHONY_SERVICE, 0)); TelephonyManager tm2 = (TelephonyManager) context.getSystemService(PhoneFactory .getServiceName(Context.TELEPHONY_SERVICE, 1)); String vmNumber1 = (tm1 != null ? tm1.getVoiceMailNumber() : ""); String vmNumber2 = (tm2 != null ? tm2.getVoiceMailNumber() : ""); if ((ce.getPhoneNumber()).equals(CallerInfo.UNKNOWN_NUMBER)) { ce.setTempName(ce.getDisplayName()); ce.setDisplayName(context.getString(R.string.unknown)); holder.contactNumber.setVisibility(View.INVISIBLE); } else if ((ce.getPhoneNumber()).equals(CallerInfo.PRIVATE_NUMBER)) { ce.setTempName(ce.getDisplayName()); ce.setDisplayName(context.getString(R.string.private_num)); holder.contactNumber.setVisibility(View.INVISIBLE); } else if ((ce.getPhoneNumber()).equals(CallerInfo.PAYPHONE_NUMBER)) { ce.setTempName(ce.getDisplayName()); ce.setDisplayName(context.getString(R.string.payphone)); } else if (PhoneNumberUtils.extractNetworkPortion(ce.getPhoneNumber()).equals(vmNumber1) || PhoneNumberUtils.extractNetworkPortion(ce.getPhoneNumber()).equals(vmNumber2)) { ce.setTempName(ce.getDisplayName()); //save the ori name when the displayName changed. ce.setDisplayName(context.getString(R.string.voicemail)); } else if (!TextUtils.isEmpty(ce.getTempName())) { ce.setDisplayName(ce.getTempName()); } } Log.d(TAG, "getView mPhoneNumber:" + ce.getPhoneNumber() + " ce.mDisplayName:" + ce.getDisplayName() + " mSearchStr:" + mSearchStr); if (mSearchStr != null && !"".equals(mSearchStr)) { if(holder != null ) { if (ce.isPhoneNumberMatched() && holder.contactNumber != null) { // make click reflection a little faster Start // String phone_number = ce.mPhoneNumber.replaceAll(mSearchStr // .replaceAll("[*]", "[*]").replaceAll("[+]", "[+]"), // "<font color='red'>" + mSearchStr + "</font>"); // contactNumber.setText(Html.fromHtml(phone_number)); holder.contactNumber.setText(transferStringBySearchWord(SpecialTextViewTool.commaSemicolonToPW(ce.getPhoneNumber()), SpecialTextViewTool.commaSemicolonToPW(mSearchStr))); // make click reflection a little faster End } else { holder.contactNumber.setText(SpecialTextViewTool.commaSemicolonToPW(ce.getPhoneNumber())); } if (holder.contactName != null) { if (ce.isNameMatched()) { Log.d(TAG, "getView is name matched!"); StringBuffer sb = new StringBuffer(ce.getDisplayName()); insertHtmlTag(sb, mSearchStr.length()); holder.contactName.setText(Html.fromHtml(sb.toString())); } else if (ce.isFullNameMatched()) { Log.d(TAG, "getView is full name matched!"); int echoIndex = 1; int remainLength = mSearchStr.length(); if (ce.getSpellNames() != null) { for (int i = 0; i < ce.getSpellNames().length; i++) { if (ce.getSpellNames()[i] != null) { remainLength = remainLength - ce.getSpellNames()[i].length(); } if ((remainLength) > 0) { echoIndex++; } else { break; } } } StringBuffer sb = new StringBuffer(ce.getDisplayName()); insertHtmlTag(sb, echoIndex); holder.contactName.setText(Html.fromHtml(sb.toString())); } else { holder.contactName.setText(ce.getDisplayName()); } } } } else{ if (holder.contactNumber != null) { holder.contactNumber.setText(SpecialTextViewTool.commaSemicolonToPW(ce.getPhoneNumber())); } if (holder.contactName != null) { holder.contactName.setText(ce.getDisplayName()); } } return convertView; } private void insertHtmlTag(StringBuffer sb, int endIndex) { try { sb.insert(endIndex, "</font>"); sb.insert(0, "<font color='red'>"); } catch (Exception e) { Log.e(TAG, "insertHtmlTag", e); Log.e(TAG, "insertHtmlTag endIndex:" + String.valueOf(endIndex)); Log.e(TAG, "insertHtmlTag sb:" + sb.toString()); } } /** * filter mAdapter * * @param constraint * @param mCustomArrayList */ public void filter(String constraint, ArrayList<ContactEntity> mCustomArrayList) { if (mCustomArrayList.size() > 0) { binSearch(constraint, mCustomArrayList); notifyDataSetChanged(); } } /** * Binsearch. * * @param constraint The string to compare with. * @param mCustomArrayList */ private void binSearch(String constraint, ArrayList<ContactEntity> mCustomArrayList) { Log.d(TAG, "binSearch"); if (TextUtils.isEmpty(constraint)) { mSearchStr = ""; setList(mCustomArrayList); } else { mList.clear(); // intelligent match ContactEntity contact; for (int i = 0; i < mCustomArrayList.size(); i++) { contact = mCustomArrayList.get(i); /* * we need to judge both number match or name match. */ // whether phone number is matched or not if (contact != null) { contact.setPhoneNumberMatched(false); contact.setNameMatched(false); contact.setFullNameMatched(false); if (contact.getPhoneNumber() != null && (-1 != contact.getPhoneNumber().replace("-", "").indexOf(constraint))) { contact.setPhoneNumberMatched(true); mList.add(contact); } // whether name is matched or not if (nameMatch(contact.getSpellNames(), constraint)) { contact.setNameMatched(true); if (!mList.contains(contact)) { mList.add(contact); } } else if (fullNameMatch(contact.getSpellName(), constraint)) { contact.setFullNameMatched(true); if (!mList.contains(contact)) { mList.add(contact); } } } } mSearchStr = constraint; } mPhotoLoader.clear(); } /** * Match Rule: The initial letter in every Chinese character being matched * * @param spellNames * @param constraint The numbers that user pressed. * @return return true if name matched. */ private boolean nameMatch(String[] spellNames, String constraint) { if (spellNames == null || constraint == null) { return false; } // number -- alphabet if (constraint.length() > spellNames.length) { return false; } boolean isMatched = false; int size = constraint.length(); /* * get the first character in one chinese character, and compare it with * the corresponding character in the constraint. if matched, continue * it; otherwise return false. */ for (int i = 0; i < size; i++) { String spell = spellNames[i]; try { // get every character in the constraint if (isInvolved(spell.charAt(0), constraint.charAt(i))) { isMatched = true; continue; } } catch (NumberFormatException nfe) { /* * if NumberFormatException occurred, we can conclude that maybe * other keys was pressed by user, so we compare the key value * with the one character in the constraint directly. */ if (spell.charAt(0) == constraint.charAt(i)) { isMatched = true; continue; } } isMatched = false; break; } return isMatched; } /** * Match Rule: The full letter in every Chinese character being matched * * @param mSpellName * @param constraint * @return true if full name matched. */ private boolean fullNameMatch(String mSpellName, String constraint) { if (mSpellName == null || constraint == null) { return false; } if (constraint.length() > mSpellName.length()) { return false; } boolean isMatched = false; for (int i = 0; i < constraint.length(); i++) { try { if (isInvolved(mSpellName.charAt(i), constraint.charAt(i))) { isMatched = true; continue; } } catch (NumberFormatException e) { if (mSpellName.charAt(i) == constraint.charAt(i)) { isMatched = true; continue; } } isMatched = false; break; } return isMatched; } /** * to decide whether the character is in the characters that the special * number stated. * * @param ch * @param number the number button, related index of NUMBER_ALPHABETS * @return */ private boolean isInvolved(char ch, char inputChar) throws NumberFormatException{ Log.d(TAG, "--isInvolved(ch = " + ch + ", inputChar = " + inputChar + ")..."); if (ch == inputChar) { return true; } if (inputChar < '2' || inputChar > '9' ) { return false; } int number = inputChar -'0'; Log.d(TAG, "inputNumber:"+number); int index = number - 2; if (index < 0 || index >= NUMBER_ALPHABETS.length) { return false; } if (ch >='A' && ch <='Z') { ch = (char)(ch + ('a'-'A')); } for (int i = 0; i < NUMBER_ALPHABETS[index].length; i++) { if (NUMBER_ALPHABETS[index][i] == ch) { return true; } } return false; } // make click reflection a little faster Start private SpannableString transferStringBySearchWord(String phoneNum, String searchWord) { String mPhoneNum = new String(phoneNum); SpannableString result = new SpannableString(mPhoneNum); int length = searchWord.length(); int index = mPhoneNum.indexOf(searchWord); while (index != -1) { result.setSpan(new ForegroundColorSpan(Color.RED), index, index + length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); index = mPhoneNum.indexOf(searchWord, index + 1); } return result; } public void setList(ArrayList<ContactEntity> mCustomArrayList) { mList.clear(); mList.addAll(mCustomArrayList); mPhotoLoader.clear(); } public void controlPhotoLoader(int command) { if (mPhotoLoader != null) { switch (command) { case RESUME: mPhotoLoader.resume(); break; case PAUSE: mPhotoLoader.pause(); break; case STOP: mPhotoLoader.stop(); break; case CLEAR: mPhotoLoader.clear(); default: break; } } } }