diff --git a/res/drawable-xhdpi/button_alert_background_default.9.png b/res/drawable-xhdpi/button_alert_background_default.9.png new file mode 100644 index 000000000..b8857340d Binary files /dev/null and b/res/drawable-xhdpi/button_alert_background_default.9.png differ diff --git a/res/drawable-xhdpi/button_alert_background_over.9.png b/res/drawable-xhdpi/button_alert_background_over.9.png new file mode 100644 index 000000000..f42b202ff Binary files /dev/null and b/res/drawable-xhdpi/button_alert_background_over.9.png differ diff --git a/res/drawable/alert.xml b/res/drawable/alert.xml new file mode 100644 index 000000000..125848d4c --- /dev/null +++ b/res/drawable/alert.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/res/layout/contact.xml b/res/layout/contact.xml index 627bef0f7..040e12e04 100644 --- a/res/layout/contact.xml +++ b/res/layout/contact.xml @@ -22,22 +22,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="centerCrop" - android:adjustViewBounds="true" - android:layout_weight="1"/> - - + android:adjustViewBounds="true"/> diff --git a/res/layout/contact_delete_button.xml b/res/layout/contact_delete_button.xml new file mode 100644 index 000000000..90af7a399 --- /dev/null +++ b/res/layout/contact_delete_button.xml @@ -0,0 +1,14 @@ + + + \ No newline at end of file diff --git a/res/layout/contact_edit_row.xml b/res/layout/contact_edit_row.xml new file mode 100644 index 000000000..4c6b13a80 --- /dev/null +++ b/res/layout/contact_edit_row.xml @@ -0,0 +1,26 @@ + + + + + + + + \ No newline at end of file diff --git a/res/layout/edit_contact.xml b/res/layout/edit_contact.xml index ac8f68cc2..0e230638a 100644 --- a/res/layout/edit_contact.xml +++ b/res/layout/edit_contact.xml @@ -63,10 +63,25 @@ android:layout_height="wrap_content" android:textColor="@android:color/black" android:background="@drawable/chat_fast_address_background" - android:gravity="center" + android:gravity="left" android:paddingRight="5dp" android:inputType="textPersonName|textCapWords"/> + + + + + + \ No newline at end of file diff --git a/src/org/linphone/ContactFragment.java b/src/org/linphone/ContactFragment.java index a623423b0..680d5c135 100644 --- a/src/org/linphone/ContactFragment.java +++ b/src/org/linphone/ContactFragment.java @@ -39,7 +39,7 @@ import android.widget.TextView; */ public class ContactFragment extends Fragment implements OnClickListener { private Contact contact; - private TextView editContact, newContact; + private TextView editContact; private LayoutInflater inflater; private View view; private boolean displayChatAddressOnly = false; @@ -70,10 +70,6 @@ public class ContactFragment extends Fragment implements OnClickListener { editContact = (TextView) view.findViewById(R.id.editContact); editContact.setOnClickListener(this); - newContact = (TextView) view.findViewById(R.id.newContact); - if (newContact != null) { - newContact.setOnClickListener(this); - } return view; } @@ -186,10 +182,6 @@ public class ContactFragment extends Fragment implements OnClickListener { case R.id.editContact: LinphoneActivity.instance().editContact(contact); break; - - case R.id.newContact: - LinphoneActivity.instance().addContact("", ""); - break; } } } diff --git a/src/org/linphone/EditContactFragment.java b/src/org/linphone/EditContactFragment.java index 81e18b1ba..80c33c84d 100644 --- a/src/org/linphone/EditContactFragment.java +++ b/src/org/linphone/EditContactFragment.java @@ -1,8 +1,14 @@ package org.linphone; +import java.io.InputStream; import java.util.ArrayList; +import java.util.List; + +import org.linphone.compatibility.Compatibility; +import org.linphone.ui.AvatarWithShadow; import android.content.ContentProviderOperation; +import android.graphics.BitmapFactory; import android.os.Bundle; import android.provider.ContactsContract; import android.provider.ContactsContract.RawContacts; @@ -14,17 +20,23 @@ import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.EditText; +import android.widget.ImageView; +import android.widget.TableLayout; import android.widget.TextView; public class EditContactFragment extends Fragment { private View view; private TextView ok; private EditText displayName; + private LayoutInflater inflater; private boolean isNewContact = true; private int contactID; + private List numbersAndAddresses; public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + this.inflater = inflater; + Contact contact = null; if (getArguments() != null && getArguments().getSerializable("Contact") != null) { contact = (Contact) getArguments().getSerializable("Contact"); @@ -51,6 +63,11 @@ public class EditContactFragment extends Fragment { } else { updateExistingContact(); } + + for (NewOrUpdatedNumberOrAddress numberOrAddress : numbersAndAddresses) { + numberOrAddress.save(); + } + getFragmentManager().popBackStackImmediate(); } }); @@ -74,13 +91,85 @@ public class EditContactFragment extends Fragment { public void afterTextChanged(Editable s) { } }); + if (!isNewContact) { displayName.setText(contact.getName()); } + AvatarWithShadow contactPicture = (AvatarWithShadow) view.findViewById(R.id.contactPicture); + if (contact != null && contact.getPhotoUri() != null) { + InputStream input = Compatibility.getContactPictureInputStream(getActivity().getContentResolver(), contact.getID()); + contactPicture.setImageBitmap(BitmapFactory.decodeStream(input)); + } else { + contactPicture.setImageResource(R.drawable.unknown_small); + } + + initNumbersFields((TableLayout) view.findViewById(R.id.controls), contact); + return view; } + private void initNumbersFields(TableLayout controls, final Contact contact) { + controls.removeAllViews(); + numbersAndAddresses = new ArrayList(); + + if (contact != null) { + for (String numberOrAddress : contact.getNumerosOrAddresses()) { + boolean isSip = numberOrAddress.startsWith("sip:"); + if (isSip) { + numberOrAddress = numberOrAddress.replace("sip:", ""); + } + + final NewOrUpdatedNumberOrAddress nounoa = new NewOrUpdatedNumberOrAddress(numberOrAddress, isSip); + numbersAndAddresses.add(nounoa); + + final View view = inflater.inflate(R.layout.contact_edit_row, null); + + final EditText noa = (EditText) view.findViewById(R.id.numoraddr); + noa.setText(numberOrAddress); + 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) { + } + }); + + ImageView delete = (ImageView) view.findViewById(R.id.delete); + delete.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + nounoa.delete(); + view.setVisibility(View.GONE); + } + }); + + 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); + } + + } + } + private void createNewContact() { ArrayList ops = new ArrayList(); contactID = ops.size(); @@ -93,14 +182,15 @@ public class EditContactFragment extends Fragment { ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, contactID) .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) - .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, displayName.getText().toString()).build() + .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, displayName.getText().toString()) + .build() ); } try { getActivity().getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops); } catch (Exception e) { - + e.printStackTrace(); } } @@ -108,20 +198,140 @@ public class EditContactFragment extends Fragment { ArrayList ops = new ArrayList(); if (displayName.getText().length() > 0) { - String selectPhone = ContactsContract.Data.CONTACT_ID + "=? AND " + ContactsContract.Data.MIMETYPE + "='" + ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE + "'" ; - String[] phoneArgs = new String[] { String.valueOf(contactID) }; + String select = ContactsContract.Data.CONTACT_ID + "=? AND " + ContactsContract.Data.MIMETYPE + "='" + ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE + "'" ; + String[] args = new String[] { String.valueOf(contactID) }; ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI) - .withSelection(selectPhone, phoneArgs) + .withSelection(select, args) .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) - .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, displayName.getText().toString()).build() + .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, displayName.getText().toString()) + .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) }; + + ops.add(ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI) + .withSelection(select, args) + .build() + ); + } + + try { + getActivity().getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops); + } catch (Exception e) { + e.printStackTrace(); + } + } + + class NewOrUpdatedNumberOrAddress { + private String oldNumberOrAddress; + private String newNumberOrAddress; + private boolean isSipAddress; + + public NewOrUpdatedNumberOrAddress(boolean isSip) { + oldNumberOrAddress = null; + newNumberOrAddress = null; + isSipAddress = isSip; + } + + public NewOrUpdatedNumberOrAddress(String old, boolean isSip) { + oldNumberOrAddress = old; + newNumberOrAddress = null; + isSipAddress = isSip; + } + + public void setNewNumberOrAddress(String newN) { + newNumberOrAddress = newN; + } + + public void save() { + if (newNumberOrAddress == null || newNumberOrAddress.equals(oldNumberOrAddress)) + return; + + ArrayList ops = new ArrayList(); + + if (oldNumberOrAddress == null) { + // New number to add + addNewNumber(ops); + } else { + // Old number to update + updateNumber(ops); + } + + try { + getActivity().getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void delete() { + //TODO + } + + 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() + ); + } 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() + ); + } + } + + private void updateNumber(ArrayList ops) { + if (isSipAddress) { + String select = ContactsContract.Data.CONTACT_ID + "=? AND " + + ContactsContract.Data.MIMETYPE + "='" + ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE + "' AND " + + ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS + "=?"; + String[] args = new String[] { String.valueOf(contactID), oldNumberOrAddress }; + + ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI) + .withSelection(select, args) + .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE) + .withValue(ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS, newNumberOrAddress) + .build() + ); + } else { + String select = ContactsContract.Data.CONTACT_ID + "=? AND " + + ContactsContract.Data.MIMETYPE + "='" + ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE + "' AND " + + ContactsContract.CommonDataKinds.Phone.NUMBER + "=?"; + String[] args = new String[] { String.valueOf(contactID), oldNumberOrAddress }; + + ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI) + .withSelection(select, args) + .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) + .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, newNumberOrAddress) + .build() + ); + } + } + } } diff --git a/src/org/linphone/LinphoneActivity.java b/src/org/linphone/LinphoneActivity.java index f9ebd4860..036ce7e17 100644 --- a/src/org/linphone/LinphoneActivity.java +++ b/src/org/linphone/LinphoneActivity.java @@ -1075,6 +1075,17 @@ public class LinphoneActivity extends FragmentActivity implements } } } + + public void removeContactFromLists(Contact contact) { + if (contactList.contains(contact)) { + contactList.remove(contact); + contactCursor = Compatibility.getContactsCursor(getContentResolver()); + } + if (sipContactList.contains(contact)) { + sipContactList.remove(contact); + sipContactCursor = Compatibility.getSIPContactsCursor(getContentResolver()); + } + } private synchronized void prepareContactsInBackground() { if (contactCursor != null) { @@ -1110,10 +1121,11 @@ public class LinphoneActivity extends FragmentActivity implements } } }); - sipContactsHandler.start(); contactList = new ArrayList(); sipContactList = new ArrayList(); + + sipContactsHandler.start(); } private void initInCallMenuLayout(boolean callTransfer) {