summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/com/android/contacts/editor/ContactEditorFragment.java158
-rw-r--r--src/com/android/contacts/editor/RawContactEditorView.java2
-rw-r--r--src/com/android/contacts/editor/StructuredNameEditorView.java12
-rw-r--r--src/com/android/contacts/editor/TextFieldsEditorView.java4
-rw-r--r--src/com/android/contacts/model/RawContactDeltaList.java20
-rw-r--r--tests/src/com/android/contacts/RawContactDeltaListTests.java7
-rw-r--r--tests/src/com/android/contacts/RawContactModifierTests.java13
7 files changed, 146 insertions, 70 deletions
diff --git a/src/com/android/contacts/editor/ContactEditorFragment.java b/src/com/android/contacts/editor/ContactEditorFragment.java
index 916ae7096..da0d91e6b 100644
--- a/src/com/android/contacts/editor/ContactEditorFragment.java
+++ b/src/com/android/contacts/editor/ContactEditorFragment.java
@@ -67,26 +67,27 @@ import com.android.contacts.R;
import com.android.contacts.activities.ContactEditorAccountsChangedActivity;
import com.android.contacts.activities.ContactEditorActivity;
import com.android.contacts.activities.JoinContactActivity;
+import com.android.contacts.common.model.AccountTypeManager;
+import com.android.contacts.common.model.ValuesDelta;
+import com.android.contacts.common.model.account.AccountType;
+import com.android.contacts.common.model.account.AccountWithDataSet;
+import com.android.contacts.common.model.account.GoogleAccountType;
+import com.android.contacts.common.util.AccountsListAdapter;
+import com.android.contacts.common.util.AccountsListAdapter.AccountListFilter;
import com.android.contacts.detail.PhotoSelectionHandler;
import com.android.contacts.editor.AggregationSuggestionEngine.Suggestion;
import com.android.contacts.editor.Editor.EditorListener;
-import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.model.Contact;
import com.android.contacts.model.ContactLoader;
import com.android.contacts.model.RawContact;
import com.android.contacts.model.RawContactDelta;
-import com.android.contacts.common.model.ValuesDelta;
import com.android.contacts.model.RawContactDeltaList;
import com.android.contacts.model.RawContactModifier;
-import com.android.contacts.common.model.account.AccountType;
-import com.android.contacts.common.model.account.AccountWithDataSet;
-import com.android.contacts.common.model.account.GoogleAccountType;
-import com.android.contacts.common.util.AccountsListAdapter;
-import com.android.contacts.common.util.AccountsListAdapter.AccountListFilter;
import com.android.contacts.util.ContactPhotoUtils;
import com.android.contacts.util.HelpUtils;
import com.android.contacts.util.UiClosables;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
import java.io.File;
import java.util.ArrayList;
@@ -118,6 +119,11 @@ public class ContactEditorFragment extends Fragment implements
private static final String KEY_NEW_LOCAL_PROFILE = "newLocalProfile";
private static final String KEY_IS_USER_PROFILE = "isUserProfile";
private static final String KEY_UPDATED_PHOTOS = "updatedPhotos";
+ private static final String KEY_IS_EDIT = "isEdit";
+ private static final String KEY_HAS_NEW_CONTACT = "hasNewContact";
+ private static final String KEY_NEW_CONTACT_READY = "newContactDataReady";
+ private static final String KEY_EXISTING_CONTACT_READY = "existingContactDataReady";
+ private static final String KEY_RAW_CONTACTS = "rawContacts";
public static final String SAVE_MODE_EXTRA_KEY = "saveMode";
@@ -236,6 +242,21 @@ public class ContactEditorFragment extends Fragment implements
private int mStatus;
+ // Whether to show the new contact blank form and if it's corresponding delta is ready.
+ private boolean mHasNewContact = false;
+ private boolean mNewContactDataReady = false;
+
+ // Whether it's an edit of existing contact and if it's corresponding delta is ready.
+ private boolean mIsEdit = false;
+ private boolean mExistingContactDataReady = false;
+
+ // This is used to pre-populate the editor with a display name when a user edits a read-only
+ // contact.
+ private String mDefaultDisplayName;
+
+ // Used to temporarily store existing contact data during a rebind call (i.e. account switch)
+ private ImmutableList<RawContact> mRawContacts;
+
private AggregationSuggestionEngine mAggregationSuggestionEngine;
private long mAggregationSuggestionsRawContactId;
private View mAggregationSuggestionView;
@@ -365,10 +386,7 @@ public class ContactEditorFragment extends Fragment implements
validateAction(mAction);
- // Handle initial actions only when existing state missing
- final boolean hasIncomingState = savedInstanceState != null;
-
- if (mState == null) {
+ if (mState.isEmpty()) {
// The delta list may not have finished loading before orientation change happens.
// In this case, there will be a saved state but deltas will be missing. Reload from
// database.
@@ -384,8 +402,12 @@ public class ContactEditorFragment extends Fragment implements
bindEditors();
}
- if (!hasIncomingState) {
- if (Intent.ACTION_INSERT.equals(mAction)) {
+ // Handle initial actions only when existing state missing
+ if (savedInstanceState == null) {
+ if (Intent.ACTION_EDIT.equals(mAction)) {
+ mIsEdit = true;
+ } else if (Intent.ACTION_INSERT.equals(mAction)) {
+ mHasNewContact = true;
final Account account = mIntentExtras == null ? null :
(Account) mIntentExtras.getParcelable(Intents.Insert.ACCOUNT);
final String dataSet = mIntentExtras == null ? null :
@@ -468,20 +490,34 @@ public class ContactEditorFragment extends Fragment implements
mNewLocalProfile = savedState.getBoolean(KEY_NEW_LOCAL_PROFILE);
mIsUserProfile = savedState.getBoolean(KEY_IS_USER_PROFILE);
mUpdatedPhotos = savedState.getParcelable(KEY_UPDATED_PHOTOS);
+ mIsEdit = savedState.getBoolean(KEY_IS_EDIT);
+ mHasNewContact = savedState.getBoolean(KEY_HAS_NEW_CONTACT);
+ mNewContactDataReady = savedState.getBoolean(KEY_NEW_CONTACT_READY);
+ mExistingContactDataReady = savedState.getBoolean(KEY_EXISTING_CONTACT_READY);
+ mRawContacts = ImmutableList.copyOf(savedState.<RawContact>getParcelableArrayList(
+ KEY_RAW_CONTACTS));
+
+ }
+
+ // mState can still be null because it may not have have finished loading before
+ // onSaveInstanceState was called.
+ if (mState == null) {
+ mState = new RawContactDeltaList();
}
}
- public void setData(Contact data) {
+ public void setData(Contact contact) {
+
// If we have already loaded data, we do not want to change it here to not confuse the user
- if (mState != null) {
+ if (!mState.isEmpty()) {
Log.v(TAG, "Ignoring background change. This will have to be rebased later");
return;
}
// See if this edit operation needs to be redirected to a custom editor
- ImmutableList<RawContact> rawContacts = data.getRawContacts();
- if (rawContacts.size() == 1) {
- RawContact rawContact = rawContacts.get(0);
+ mRawContacts = contact.getRawContacts();
+ if (mRawContacts.size() == 1) {
+ RawContact rawContact = mRawContacts.get(0);
String type = rawContact.getAccountTypeString();
String dataSet = rawContact.getDataSet();
AccountType accountType = rawContact.getAccountType(mContext);
@@ -499,7 +535,18 @@ public class ContactEditorFragment extends Fragment implements
}
}
- bindEditorsForExistingContact(data);
+ // Check for writable raw contacts. If there are none, then we need to create one so user
+ // can edit. For the user profile case, there is already an editable contact.
+ if (!contact.isUserProfile() && !contact.isWritableContact(mContext)) {
+ mHasNewContact = true;
+
+ // This is potentially an asynchronous call and will add deltas to list.
+ selectAccountAndCreateContact();
+ }
+
+ // This also adds deltas to list
+ bindEditorsForExistingContact(contact.getDisplayName(), contact.isUserProfile(),
+ mRawContacts);
}
@Override
@@ -507,15 +554,17 @@ public class ContactEditorFragment extends Fragment implements
mListener.onCustomEditContactActivityRequested(account, uri, null, false);
}
- private void bindEditorsForExistingContact(Contact contact) {
+ private void bindEditorsForExistingContact(String displayName, boolean isUserProfile,
+ ImmutableList<RawContact> rawContacts) {
setEnabled(true);
+ mDefaultDisplayName = displayName;
- mState = contact.createRawContactDeltaList();
+ mState.addAll(rawContacts.iterator());
setIntentExtras(mIntentExtras);
mIntentExtras = null;
// For user profile, change the contacts query URI
- mIsUserProfile = contact.isUserProfile();
+ mIsUserProfile = isUserProfile;
boolean localProfileExists = false;
if (mIsUserProfile) {
@@ -539,7 +588,7 @@ public class ContactEditorFragment extends Fragment implements
}
}
mRequestFocus = true;
-
+ mExistingContactDataReady = true;
bindEditors();
}
@@ -649,8 +698,13 @@ public class ContactEditorFragment extends Fragment implements
mListener.onCustomCreateContactActivityRequested(newAccount, mIntentExtras);
}
} else {
- mState = null;
+ mExistingContactDataReady = false;
+ mNewContactDataReady = false;
+ mState = new RawContactDeltaList();
bindEditorsForNewContact(newAccount, newAccountType, oldState, oldAccountType);
+ if (mIsEdit) {
+ bindEditorsForExistingContact(mDefaultDisplayName, mIsUserProfile, mRawContacts);
+ }
}
}
@@ -671,7 +725,8 @@ public class ContactEditorFragment extends Fragment implements
rawContact.setAccountToLocal();
}
- RawContactDelta insert = new RawContactDelta(ValuesDelta.fromAfter(rawContact.getValues()));
+ final ValuesDelta valuesDelta = ValuesDelta.fromAfter(rawContact.getValues());
+ final RawContactDelta insert = new RawContactDelta(valuesDelta);
if (oldState == null) {
// Parse any values from incoming intent
RawContactModifier.parseExtras(mContext, newAccountType, insert, mIntentExtras);
@@ -694,23 +749,25 @@ public class ContactEditorFragment extends Fragment implements
insert.setProfileQueryUri();
}
- if (mState == null) {
- // Create state if none exists yet
- mState = RawContactDeltaList.fromSingle(insert);
- } else {
- // Add contact onto end of existing state
- mState.add(insert);
- }
+ mState.add(insert);
mRequestFocus = true;
+ mNewContactDataReady = true;
bindEditors();
}
private void bindEditors() {
// bindEditors() can only bind views if there is data in mState, so immediately return
// if mState is null
- if (mState == null) {
+ if (mState.isEmpty()) {
+ return;
+ }
+
+ // Check if delta list is ready. Delta list is populated from existing data and when
+ // editing an read-only contact, it's also populated with newly created data for the
+ // blank form. When the data is not ready, skip. This method will be called multiple times.
+ if ((mIsEdit && !mExistingContactDataReady) || (mHasNewContact && !mNewContactDataReady)) {
return;
}
@@ -724,6 +781,7 @@ public class ContactEditorFragment extends Fragment implements
Context.LAYOUT_INFLATER_SERVICE);
final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
int numRawContacts = mState.size();
+
for (int i = 0; i < numRawContacts; i++) {
// TODO ensure proper ordering of entities in the list
final RawContactDelta rawContactDelta = mState.get(i);
@@ -741,10 +799,10 @@ public class ContactEditorFragment extends Fragment implements
editor = (RawContactEditorView) inflater.inflate(R.layout.raw_contact_editor_view,
mContent, false);
}
- if (Intent.ACTION_INSERT.equals(mAction) && numRawContacts == 1) {
+ if (mHasNewContact && !mNewLocalProfile) {
final List<AccountWithDataSet> accounts =
AccountTypeManager.getInstance(mContext).getAccounts(true);
- if (accounts.size() > 1 && !mNewLocalProfile) {
+ if (accounts.size() > 1) {
addAccountSwitcher(mState.get(0), editor);
} else {
disableAccountSwitcher(editor);
@@ -787,12 +845,13 @@ public class ContactEditorFragment extends Fragment implements
}
};
- final TextFieldsEditorView nameEditor = rawContactEditor.getNameEditor();
+ final StructuredNameEditorView nameEditor = rawContactEditor.getNameEditor();
if (mRequestFocus) {
nameEditor.requestFocus();
mRequestFocus = false;
}
nameEditor.setEditorListener(listener);
+ nameEditor.setDisplayName(mDefaultDisplayName);
final TextFieldsEditorView phoneticNameEditor =
rawContactEditor.getPhoneticNameEditor();
@@ -959,7 +1018,7 @@ public class ContactEditorFragment extends Fragment implements
doneMenu.setVisible(false);
// Split only if more than one raw profile and not a user profile
- splitMenu.setVisible(mState != null && mState.size() > 1 && !isEditingUserProfile());
+ splitMenu.setVisible(mState.size() > 1 && !isEditingUserProfile());
// Cannot join a user profile
joinMenu.setVisible(!isEditingUserProfile());
@@ -1032,7 +1091,7 @@ public class ContactEditorFragment extends Fragment implements
* performing user actions.
*/
private boolean hasValidState() {
- return mState != null && mState.size() > 0;
+ return mState.size() > 0;
}
/**
@@ -1117,7 +1176,7 @@ public class ContactEditorFragment extends Fragment implements
}
private boolean revert() {
- if (mState == null || !hasPendingChanges()) {
+ if (mState.isEmpty() || !hasPendingChanges()) {
doRevertAction();
} else {
CancelEditDialogFragment.show(this);
@@ -1193,7 +1252,7 @@ public class ContactEditorFragment extends Fragment implements
// If this was in INSERT, we are changing into an EDIT now.
// If it already was an EDIT, we are changing to the new Uri now
- mState = null;
+ mState = new RawContactDeltaList();
load(Intent.ACTION_EDIT, contactLookupUri, null);
mStatus = Status.LOADING;
getLoaderManager().restartLoader(LOADER_DATA, null, mDataLoaderListener);
@@ -1393,12 +1452,10 @@ public class ContactEditorFragment extends Fragment implements
* Returns the contact ID for the currently edited contact or 0 if the contact is new.
*/
protected long getContactId() {
- if (mState != null) {
- for (RawContactDelta rawContact : mState) {
- Long contactId = rawContact.getValues().getAsLong(RawContacts.CONTACT_ID);
- if (contactId != null) {
- return contactId;
- }
+ for (RawContactDelta rawContact : mState) {
+ Long contactId = rawContact.getValues().getAsLong(RawContacts.CONTACT_ID);
+ if (contactId != null) {
+ return contactId;
}
}
return 0;
@@ -1435,7 +1492,7 @@ public class ContactEditorFragment extends Fragment implements
public void onAggregationSuggestionChange() {
Activity activity = getActivity();
if ((activity != null && activity.isFinishing())
- || !isVisible() || mState == null || mStatus != Status.EDITING) {
+ || !isVisible() || mState.isEmpty() || mStatus != Status.EDITING) {
return;
}
@@ -1600,6 +1657,11 @@ public class ContactEditorFragment extends Fragment implements
outState.putBoolean(KEY_IS_USER_PROFILE, mIsUserProfile);
outState.putInt(KEY_STATUS, mStatus);
outState.putParcelable(KEY_UPDATED_PHOTOS, mUpdatedPhotos);
+ outState.putBoolean(KEY_HAS_NEW_CONTACT, mHasNewContact);
+ outState.putBoolean(KEY_IS_EDIT, mIsEdit);
+ outState.putBoolean(KEY_NEW_CONTACT_READY, mNewContactDataReady);
+ outState.putBoolean(KEY_EXISTING_CONTACT_READY, mExistingContactDataReady);
+ outState.putParcelableArrayList(KEY_RAW_CONTACTS, Lists.newArrayList(mRawContacts));
super.onSaveInstanceState(outState);
}
@@ -1778,7 +1840,7 @@ public class ContactEditorFragment extends Fragment implements
@Override
public void onSplitContactConfirmed() {
- if (mState == null) {
+ if (mState.isEmpty()) {
// This may happen when this Fragment is recreated by the system during users
// confirming the split action (and thus this method is called just before onCreate()),
// for example.
diff --git a/src/com/android/contacts/editor/RawContactEditorView.java b/src/com/android/contacts/editor/RawContactEditorView.java
index d069c8d53..909930788 100644
--- a/src/com/android/contacts/editor/RawContactEditorView.java
+++ b/src/com/android/contacts/editor/RawContactEditorView.java
@@ -418,7 +418,7 @@ public class RawContactEditorView extends BaseRawContactEditorView {
return -1;
}
- public TextFieldsEditorView getNameEditor() {
+ public StructuredNameEditorView getNameEditor() {
return mName;
}
diff --git a/src/com/android/contacts/editor/StructuredNameEditorView.java b/src/com/android/contacts/editor/StructuredNameEditorView.java
index f7090212c..4d7259857 100644
--- a/src/com/android/contacts/editor/StructuredNameEditorView.java
+++ b/src/com/android/contacts/editor/StructuredNameEditorView.java
@@ -200,6 +200,18 @@ public class StructuredNameEditorView extends TextFieldsEditorView {
}
}
+ /**
+ * Set the display name onto the text field directly. This does not affect the underlying
+ * data structure so it is similar to the user typing the value in on the field directly.
+ *
+ * @param name The name to set on the text field.
+ */
+ public void setDisplayName(String name) {
+ // For now, assume the first text field is the name.
+ // TODO: Find a better way to get a hold of the name field.
+ super.setValue(0, name);
+ }
+
@Override
protected Parcelable onSaveInstanceState() {
SavedState state = new SavedState(super.onSaveInstanceState());
diff --git a/src/com/android/contacts/editor/TextFieldsEditorView.java b/src/com/android/contacts/editor/TextFieldsEditorView.java
index 0b47021d2..95eb0c162 100644
--- a/src/com/android/contacts/editor/TextFieldsEditorView.java
+++ b/src/com/android/contacts/editor/TextFieldsEditorView.java
@@ -174,6 +174,10 @@ public class TextFieldsEditorView extends LabeledEditorView {
}
}
+ public void setValue(int field, String value) {
+ mFieldEditTexts[field].setText(value);
+ }
+
@Override
public void setValues(DataKind kind, ValuesDelta entry, RawContactDelta state, boolean readOnly,
ViewIdGenerator vig) {
diff --git a/src/com/android/contacts/model/RawContactDeltaList.java b/src/com/android/contacts/model/RawContactDeltaList.java
index 600a7518f..1a9eb718c 100644
--- a/src/com/android/contacts/model/RawContactDeltaList.java
+++ b/src/com/android/contacts/model/RawContactDeltaList.java
@@ -49,17 +49,7 @@ public class RawContactDeltaList extends ArrayList<RawContactDelta> implements P
private boolean mSplitRawContacts;
private long[] mJoinWithRawContactIds;
- private RawContactDeltaList() {
- }
-
- /**
- * Create an {@link RawContactDeltaList} that contains the given {@link RawContactDelta},
- * usually when inserting a new {@link Contacts} entry.
- */
- public static RawContactDeltaList fromSingle(RawContactDelta delta) {
- final RawContactDeltaList state = new RawContactDeltaList();
- state.add(delta);
- return state;
+ public RawContactDeltaList() {
}
/**
@@ -85,6 +75,11 @@ public class RawContactDeltaList extends ArrayList<RawContactDelta> implements P
*/
public static RawContactDeltaList fromIterator(Iterator<?> iterator) {
final RawContactDeltaList state = new RawContactDeltaList();
+ state.addAll(iterator);
+ return state;
+ }
+
+ public void addAll(Iterator<?> iterator) {
// Perform background query to pull contact details
while (iterator.hasNext()) {
// Read all contacts into local deltas to prepare for edits
@@ -93,9 +88,8 @@ public class RawContactDeltaList extends ArrayList<RawContactDelta> implements P
? RawContact.createFrom((Entity) nextObject)
: (RawContact) nextObject;
final RawContactDelta rawContactDelta = RawContactDelta.fromBefore(before);
- state.add(rawContactDelta);
+ add(rawContactDelta);
}
- return state;
}
/**
diff --git a/tests/src/com/android/contacts/RawContactDeltaListTests.java b/tests/src/com/android/contacts/RawContactDeltaListTests.java
index a8c445b88..6a75b818a 100644
--- a/tests/src/com/android/contacts/RawContactDeltaListTests.java
+++ b/tests/src/com/android/contacts/RawContactDeltaListTests.java
@@ -45,6 +45,7 @@ import com.google.common.collect.Lists;
import java.lang.reflect.Field;
import java.util.ArrayList;
+import java.util.Collections;
/**
* Tests for {@link RawContactDeltaList} which focus on "diff" operations that should
@@ -112,10 +113,8 @@ public class RawContactDeltaListTests extends AndroidTestCase {
}
static RawContactDeltaList buildSet(RawContactDelta... deltas) {
- final RawContactDeltaList set = RawContactDeltaList.fromSingle(deltas[0]);
- for (int i = 1; i < deltas.length; i++) {
- set.add(deltas[i]);
- }
+ final RawContactDeltaList set = new RawContactDeltaList();
+ Collections.addAll(set, deltas);
return set;
}
diff --git a/tests/src/com/android/contacts/RawContactModifierTests.java b/tests/src/com/android/contacts/RawContactModifierTests.java
index 91358ca37..ce69b55bc 100644
--- a/tests/src/com/android/contacts/RawContactModifierTests.java
+++ b/tests/src/com/android/contacts/RawContactModifierTests.java
@@ -521,7 +521,9 @@ public class RawContactModifierTests extends AndroidTestCase {
// Try creating a contact without any child entries
final RawContactDelta state = getRawContact(null);
- final RawContactDeltaList set = RawContactDeltaList.fromSingle(state);
+ final RawContactDeltaList set = new RawContactDeltaList();
+ set.add(state);
+
// Build diff, expecting single insert
final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
@@ -549,7 +551,8 @@ public class RawContactModifierTests extends AndroidTestCase {
// Try creating a contact with single empty entry
final RawContactDelta state = getRawContact(null);
RawContactModifier.insertChild(state, kindPhone, typeHome);
- final RawContactDeltaList set = RawContactDeltaList.fromSingle(state);
+ final RawContactDeltaList set = new RawContactDeltaList();
+ set.add(state);
// Build diff, expecting two insert operations
final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
@@ -593,7 +596,8 @@ public class RawContactModifierTests extends AndroidTestCase {
second.put(Phone.NUMBER, TEST_PHONE);
final RawContactDelta state = getRawContact(TEST_ID, first, second);
- final RawContactDeltaList set = RawContactDeltaList.fromSingle(state);
+ final RawContactDeltaList set = new RawContactDeltaList();
+ set.add(state);
// Build diff, expecting no changes
final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
@@ -658,7 +662,8 @@ public class RawContactModifierTests extends AndroidTestCase {
first.put(Phone.NUMBER, TEST_PHONE);
final RawContactDelta state = getRawContact(TEST_ID, first);
- final RawContactDeltaList set = RawContactDeltaList.fromSingle(state);
+ final RawContactDeltaList set = new RawContactDeltaList();
+ set.add(state);
// Build diff, expecting no changes
final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();