From f21c6ecb747a512c23255c599c60c95fab82642b Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 7 Nov 2012 16:57:55 +0100 Subject: [PATCH] In-app contact editor finished (misses add field icon) --- res/drawable/sym_action_add.png | Bin 0 -> 1575 bytes res/layout/contact_add_row.xml | 26 ++ res/layout/contact_delete_button.xml | 2 +- res/layout/edit_contact.xml | 79 +++--- res/values-FR/strings.xml | 4 + res/values/custom.xml | 1 + res/values/strings.xml | 4 +- src/org/linphone/ChatStorage.java | 3 + src/org/linphone/EditContactFragment.java | 238 ++++++++++++------ src/org/linphone/LinphoneActivity.java | 2 +- .../linphone/compatibility/ApiFivePlus.java | 25 +- 11 files changed, 261 insertions(+), 123 deletions(-) create mode 100644 res/drawable/sym_action_add.png create mode 100644 res/layout/contact_add_row.xml diff --git a/res/drawable/sym_action_add.png b/res/drawable/sym_action_add.png new file mode 100644 index 0000000000000000000000000000000000000000..6e028b20b3ec898485bcf6bc55b39b6f1c7733cd GIT binary patch literal 1575 zcmV+?2H5$DP)(RCwC#nO#U@M-<0LaR}qS5$mwEusYBPW-ntx2?O$-rT9@0~mIoBy0SGjmgNadBbZwNz@}!Bm7ULjT{O z%kr&YY-}u*pP!$bWHMg~0pc6L2CJ&7OifLVsjjXz<>lp~s`u>d z%zJ!%eDC1kAarzeWKK>_W&ry&pkK1wjX_ULOf*5c#{e9utE)5h_4THExd@X#a@iQw+;ZVnt}c6LlW9)FF_d@?jN^!nPM!{KlMO8y3A-ObI-DTT|*%KjEM8$7`QO^d^A zJ{}w#j20Yva&q!60AD~^4}s|p1kMyCc%Q#nH+(u{RN+1Nx`C^tz%c^%L!r>Cf0v2fcG@o%o(zofyRCIrTKjjwAwy3y(!`ENpx4*x?KUt8)1?r6g#7B2v zbfB7|oL11P9maJXfJ&ey^DyC@&bi%gnh#NEv>-}HA`v%K{R3X%<-|k9S>rX; zhkc66U+5OrLb(1}M-*pbIYt(Y$OcB{{l31wL|!2es*WH!c&RXFMd|CaBvdE+Gxr&ZN}i#Irtm>FL*NXjtMR#P@8(xC{Sv(~osju}Zs8CV=s(B3%Sl6bpy}a8nnyW5_Z@u3I*_|@ZyX~rphr)=*P64^sK6tu z9V?fLsSX;Bw6wG&mY0{)o@qa3XJyZ!S51^lu+tD^Kt~m&xF=_5U73I}Cxmqcv%bEb z0+i?3Rz!&sk|aLU$FI8E`zPplCTI>dHaxw!e7d>0nFhs4Cm>Xrt06ln@5@pT;9ho) z<@Gab@qD1)IEPL`7i5q_aNf|<5Vm<`$Ji+W7=z=}g;gN>~l=X_jjukc4ZqCrC zEXu_J=F;(%jd4lmVgUd4ic(Y>FdlIWb^@w z`x6O^a#+wYTu$gRdH<8IraIKw6UpV_R-JHCZ~`p9*;!8HoIWoX|B@?07om&LIi + + + + + + + \ No newline at end of file diff --git a/res/layout/contact_delete_button.xml b/res/layout/contact_delete_button.xml index 90af7a399..b8736ee91 100644 --- a/res/layout/contact_delete_button.xml +++ b/res/layout/contact_delete_button.xml @@ -2,7 +2,7 @@ - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/res/values-FR/strings.xml b/res/values-FR/strings.xml index 332623aae..6a60d9ce6 100644 --- a/res/values-FR/strings.xml +++ b/res/values-FR/strings.xml @@ -341,4 +341,8 @@ Calibration de l\'annulateur d\'écho en cours + Supprimer contact + Adresse SIP + Numéro de téléphone + diff --git a/res/values/custom.xml b/res/values/custom.xml index 439d2b3c4..e01d010a4 100644 --- a/res/values/custom.xml +++ b/res/values/custom.xml @@ -6,6 +6,7 @@ linphone-mms-%s.jpg Linphone + Linphone Linphone Starting up Registered to %s diff --git a/res/values/strings.xml b/res/values/strings.xml index 4cdbb60a6..e5acbd86d 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -388,5 +388,7 @@ wants to share it\'s presence status with you and be aware of yours. Echo canceller calibration in progress - + Delete contact + SIP address + Phone number diff --git a/src/org/linphone/ChatStorage.java b/src/org/linphone/ChatStorage.java index 5625b120f..9e8c04bf8 100644 --- a/src/org/linphone/ChatStorage.java +++ b/src/org/linphone/ChatStorage.java @@ -88,6 +88,9 @@ public class ChatStorage { } public int saveMessage(String from, String to, Bitmap image) { + if (image == null) + return -1; + ContentValues values = new ContentValues(); if (from.equals("")) { values.put("localContact", from); diff --git a/src/org/linphone/EditContactFragment.java b/src/org/linphone/EditContactFragment.java index be3feef05..7fa628241 100644 --- a/src/org/linphone/EditContactFragment.java +++ b/src/org/linphone/EditContactFragment.java @@ -8,6 +8,7 @@ import org.linphone.compatibility.Compatibility; import org.linphone.ui.AvatarWithShadow; import android.content.ContentProviderOperation; +import android.database.Cursor; import android.graphics.BitmapFactory; import android.os.Bundle; import android.provider.ContactsContract; @@ -29,10 +30,13 @@ public class EditContactFragment extends Fragment { private TextView ok; private EditText displayName; private LayoutInflater inflater; + private View deleteContact; private boolean isNewContact = true; private int contactID; private List numbersAndAddresses; + private ArrayList ops; + private int firstSipAddressIndex = -1; public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { this.inflater = inflater; @@ -67,7 +71,17 @@ public class EditContactFragment extends Fragment { for (NewOrUpdatedNumberOrAddress numberOrAddress : numbersAndAddresses) { numberOrAddress.save(); } - + + try { + getActivity().getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops); + + if (isNewContact) { + LinphoneActivity.instance().prepareContactsInBackground(); + } + } catch (Exception e) { + e.printStackTrace(); + } + getFragmentManager().popBackStackImmediate(); } }); @@ -106,17 +120,23 @@ public class EditContactFragment extends Fragment { initNumbersFields((TableLayout) view.findViewById(R.id.controls), contact); + ops = new ArrayList(); + return view; } - private void initNumbersFields(TableLayout controls, final Contact contact) { + private void initNumbersFields(final TableLayout controls, final Contact contact) { controls.removeAllViews(); numbersAndAddresses = new ArrayList(); if (contact != null) { for (String numberOrAddress : contact.getNumerosOrAddresses()) { - boolean isSip = numberOrAddress.startsWith("sip:"); + final boolean isSip = numberOrAddress.startsWith("sip:"); if (isSip) { + if (firstSipAddressIndex == -1) { + firstSipAddressIndex = controls.getChildCount(); + } + numberOrAddress = numberOrAddress.replace("sip:", ""); } @@ -149,31 +169,98 @@ public class EditContactFragment extends Fragment { nounoa.delete(); numbersAndAddresses.remove(nounoa); view.setVisibility(View.GONE); + if (isSip) // Add back the add SIP row + addEmptyRowToAllowNewNumberOrAddress(controls, true); } }); controls.addView(view); } - - if (!isNewContact) { - View deleteContact = inflater.inflate(R.layout.contact_delete_button, null); - deleteContact.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - deleteExistingContact(); - LinphoneActivity.instance().removeContactFromLists(contact); - LinphoneActivity.instance().displayContacts(false); - } - }); - controls.addView(deleteContact); + } + + if (!isNewContact) { + deleteContact = inflater.inflate(R.layout.contact_delete_button, null); + deleteContact.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + deleteExistingContact(); + LinphoneActivity.instance().removeContactFromLists(contact); + LinphoneActivity.instance().displayContacts(false); + } + }); + controls.addView(deleteContact, controls.getChildCount()); + } + + // Add one for phone numbers, one for SIP address + addEmptyRowToAllowNewNumberOrAddress(controls, false); + if (firstSipAddressIndex == -1) { // Only add new SIP address field if there is no SIP address yet + firstSipAddressIndex = controls.getChildCount() - 2; // Update the value to alwas display phone numbers before SIP accounts + addEmptyRowToAllowNewNumberOrAddress(controls, true); + } + } + + private void addEmptyRowToAllowNewNumberOrAddress(final TableLayout controls, final boolean isSip) { + final View view = inflater.inflate(R.layout.contact_add_row, null); + + final NewOrUpdatedNumberOrAddress nounoa = new NewOrUpdatedNumberOrAddress(isSip); + + final EditText noa = (EditText) view.findViewById(R.id.numoraddr); + noa.setHint(isSip ? getString(R.string.sip_address) : getString(R.string.phone_number)); + noa.requestFocus(); + noa.addTextChangedListener(new TextWatcher() { + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + nounoa.setNewNumberOrAddress(noa.getText().toString()); } + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } + + @Override + public void afterTextChanged(Editable s) { + } + }); + + final ImageView add = (ImageView) view.findViewById(R.id.add); + add.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + // Add a line, and change add button for a delete button + numbersAndAddresses.add(nounoa); + add.setImageResource(R.drawable.list_delete); + add.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + numbersAndAddresses.remove(nounoa); + view.setVisibility(View.GONE); + if (isSip) // Add back the add SIP row + addEmptyRowToAllowNewNumberOrAddress(controls, true); + } + }); + if (!isSip) { // Only 1 SIP address / contact + firstSipAddressIndex++; + addEmptyRowToAllowNewNumberOrAddress(controls, false); + } + } + }); + + if (isSip) { + controls.addView(view, controls.getChildCount()); + // Move to the bottom the remove contact button + controls.removeView(deleteContact); + controls.addView(deleteContact, controls.getChildCount()); + } else { + if (firstSipAddressIndex != -1) { + controls.addView(view, firstSipAddressIndex); + } else { + controls.addView(view); + } } } private void createNewContact() { - ArrayList ops = new ArrayList(); - contactID = ops.size(); + contactID = 0; ops.add(ContentProviderOperation.newInsert(RawContacts.CONTENT_URI) .withValue(RawContacts.ACCOUNT_TYPE, null) @@ -187,17 +274,9 @@ public class EditContactFragment extends Fragment { .build() ); } - - try { - getActivity().getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops); - } catch (Exception e) { - e.printStackTrace(); - } } private void updateExistingContact() { - ArrayList ops = new ArrayList(); - if (displayName.getText().length() > 0) { String select = ContactsContract.Data.CONTACT_ID + "=? AND " + ContactsContract.Data.MIMETYPE + "='" + ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE + "'" ; String[] args = new String[] { String.valueOf(contactID) }; @@ -209,17 +288,9 @@ public class EditContactFragment extends Fragment { .build() ); } - - try { - getActivity().getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops); - } catch (Exception e) { - e.printStackTrace(); - } } private void deleteExistingContact() { - ArrayList ops = new ArrayList(); - if (displayName.getText().length() > 0) { String select = ContactsContract.Data.CONTACT_ID + "=?"; String[] args = new String[] { String.valueOf(contactID) }; @@ -237,11 +308,28 @@ public class EditContactFragment extends Fragment { } } + private String findRawContactID(String contactID) { + Cursor c = getActivity().getContentResolver().query(RawContacts.CONTENT_URI, + new String[]{RawContacts._ID}, + RawContacts.CONTACT_ID + "=?", + new String[]{contactID}, null); + if (c != null && c.moveToFirst()) { + return c.getString(c.getColumnIndex(RawContacts._ID)); + } + return null; + } + class NewOrUpdatedNumberOrAddress { private String oldNumberOrAddress; private String newNumberOrAddress; private boolean isSipAddress; + public NewOrUpdatedNumberOrAddress() { + oldNumberOrAddress = null; + newNumberOrAddress = null; + isSipAddress = false; + } + public NewOrUpdatedNumberOrAddress(boolean isSip) { oldNumberOrAddress = null; newNumberOrAddress = null; @@ -262,26 +350,16 @@ public class EditContactFragment extends Fragment { if (newNumberOrAddress == null || newNumberOrAddress.equals(oldNumberOrAddress)) return; - ArrayList ops = new ArrayList(); - if (oldNumberOrAddress == null) { // New number to add - addNewNumber(ops); + addNewNumber(); } else { // Old number to update - updateNumber(ops); + updateNumber(); } - - try { - getActivity().getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops); - } catch (Exception e) { - e.printStackTrace(); - } } public void delete() { - ArrayList ops = new ArrayList(); - if (isSipAddress) { String select = ContactsContract.Data.CONTACT_ID + "=? AND " + ContactsContract.Data.MIMETYPE + "='" + ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE + "' AND " @@ -303,39 +381,55 @@ public class EditContactFragment extends Fragment { .build() ); } - - try { - getActivity().getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops); - } catch (Exception e) { - e.printStackTrace(); - } } - private void addNewNumber(ArrayList ops) { - if (isSipAddress) { - ops.add(ContentProviderOperation. - newInsert(ContactsContract.Data.CONTENT_URI) - .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, contactID) - .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE) - .withValue(ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS, newNumberOrAddress) - .withValue(ContactsContract.CommonDataKinds.SipAddress.TYPE, ContactsContract.CommonDataKinds.SipAddress.TYPE_CUSTOM) - .withValue(ContactsContract.CommonDataKinds.SipAddress.LABEL, "Linphone") - .build() - ); + private void addNewNumber() { + if (isNewContact) { + if (isSipAddress) { + ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) + .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) + .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE) + .withValue(ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS, newNumberOrAddress) + .withValue(ContactsContract.CommonDataKinds.SipAddress.TYPE, ContactsContract.CommonDataKinds.SipAddress.TYPE_CUSTOM) + .withValue(ContactsContract.CommonDataKinds.SipAddress.LABEL, getString(R.string.addressbook_label)) + .build() + ); + } else { + ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) + .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) + .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) + .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, newNumberOrAddress) + .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_CUSTOM) + .withValue(ContactsContract.CommonDataKinds.Phone.LABEL, getString(R.string.addressbook_label)) + .build() + ); + } } else { - ops.add(ContentProviderOperation. - newInsert(ContactsContract.Data.CONTENT_URI) - .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, contactID) - .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) - .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, newNumberOrAddress) - .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_CUSTOM) - .withValue(ContactsContract.CommonDataKinds.Phone.LABEL, "Linphone") - .build() - ); + String rawContactId = findRawContactID(String.valueOf(contactID)); + + if (isSipAddress) { + ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) + .withValue(ContactsContract.Data.RAW_CONTACT_ID, rawContactId) + .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE) + .withValue(ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS, newNumberOrAddress) + .withValue(ContactsContract.CommonDataKinds.SipAddress.TYPE, ContactsContract.CommonDataKinds.SipAddress.TYPE_CUSTOM) + .withValue(ContactsContract.CommonDataKinds.SipAddress.LABEL, getString(R.string.addressbook_label)) + .build() + ); + } else { + ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) + .withValue(ContactsContract.Data.RAW_CONTACT_ID, rawContactId) + .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) + .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, newNumberOrAddress) + .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_CUSTOM) + .withValue(ContactsContract.CommonDataKinds.Phone.LABEL, getString(R.string.addressbook_label)) + .build() + ); + } } } - private void updateNumber(ArrayList ops) { + private void updateNumber() { if (isSipAddress) { String select = ContactsContract.Data.CONTACT_ID + "=? AND " + ContactsContract.Data.MIMETYPE + "='" + ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE + "' AND " diff --git a/src/org/linphone/LinphoneActivity.java b/src/org/linphone/LinphoneActivity.java index 036ce7e17..47bd00c49 100644 --- a/src/org/linphone/LinphoneActivity.java +++ b/src/org/linphone/LinphoneActivity.java @@ -1087,7 +1087,7 @@ public class LinphoneActivity extends FragmentActivity implements } } - private synchronized void prepareContactsInBackground() { + public synchronized void prepareContactsInBackground() { if (contactCursor != null) { contactCursor.close(); } diff --git a/src/org/linphone/compatibility/ApiFivePlus.java b/src/org/linphone/compatibility/ApiFivePlus.java index f1c5a9b6f..986b469c7 100644 --- a/src/org/linphone/compatibility/ApiFivePlus.java +++ b/src/org/linphone/compatibility/ApiFivePlus.java @@ -118,12 +118,23 @@ public class ApiFivePlus { return intent; } + @SuppressWarnings("resource") public static List extractContactNumbersAndAddresses(String id, ContentResolver cr) { List list = new ArrayList(); Uri uri = Data.CONTENT_URI; String[] projection = {ContactsContract.CommonDataKinds.Im.DATA}; + // Phone Numbers + Cursor c = cr.query(Phone.CONTENT_URI, new String[] { Phone.NUMBER }, Phone.CONTACT_ID + " = " + id, null, null); + if (c != null) { + while (c.moveToNext()) { + String number = c.getString(c.getColumnIndex(Phone.NUMBER)); + list.add(number); + } + c.close(); + } + // SIP addresses if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) { String selection = new StringBuilder() @@ -135,7 +146,7 @@ public class ApiFivePlus { .append("'") .toString(); projection = new String[] {ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS}; - Cursor c = cr.query(uri, projection, selection, new String[]{id}, null); + c = cr.query(uri, projection, selection, new String[]{id}, null); if (c != null) { int nbId = c.getColumnIndex(ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS); while (c.moveToNext()) { @@ -152,7 +163,7 @@ public class ApiFivePlus { .append(ContactsContract.CommonDataKinds.Im.CUSTOM_PROTOCOL) .append(") = 'sip'") .toString(); - Cursor c = cr.query(uri, projection, selection, new String[]{id}, null); + c = cr.query(uri, projection, selection, new String[]{id}, null); if (c != null) { int nbId = c.getColumnIndex(ContactsContract.CommonDataKinds.Im.DATA); while (c.moveToNext()) { @@ -161,16 +172,6 @@ public class ApiFivePlus { c.close(); } } - - // Phone Numbers - Cursor c = cr.query(Phone.CONTENT_URI, new String[] { Phone.NUMBER }, Phone.CONTACT_ID + " = " + id, null, null); - if (c != null) { - while (c.moveToNext()) { - String number = c.getString(c.getColumnIndex(Phone.NUMBER)); - list.add(number); - } - c.close(); - } return list; }