Merge "Re-use the Detail-Loader in the Editor"
diff --git a/src/com/android/contacts/model/EntitySet.java b/src/com/android/contacts/model/EntitySet.java
index 83fe338..0f4d68d 100644
--- a/src/com/android/contacts/model/EntitySet.java
+++ b/src/com/android/contacts/model/EntitySet.java
@@ -33,6 +33,7 @@
import com.android.contacts.model.EntityDelta.ValuesDelta;
import java.util.ArrayList;
+import java.util.Iterator;
/**
* Container for multiple {@link EntityDelta} objects, usually when editing
@@ -62,25 +63,32 @@
*/
public static EntitySet fromQuery(ContentResolver resolver, String selection,
String[] selectionArgs, String sortOrder) {
- EntityIterator iterator = RawContacts.newEntityIterator(resolver.query(
+ final EntityIterator iterator = RawContacts.newEntityIterator(resolver.query(
RawContactsEntity.CONTENT_URI, null, selection, selectionArgs,
sortOrder));
try {
- final EntitySet state = new EntitySet();
- // Perform background query to pull contact details
- while (iterator.hasNext()) {
- // Read all contacts into local deltas to prepare for edits
- final Entity before = iterator.next();
- final EntityDelta entity = EntityDelta.fromBefore(before);
- state.add(entity);
- }
- return state;
+ return fromIterator(iterator);
} finally {
iterator.close();
}
}
/**
+ * Create an {@link EntitySet} that contains the entities of the Iterator as before values.
+ */
+ public static EntitySet fromIterator(Iterator<Entity> iterator) {
+ final EntitySet state = new EntitySet();
+ // Perform background query to pull contact details
+ while (iterator.hasNext()) {
+ // Read all contacts into local deltas to prepare for edits
+ final Entity before = iterator.next();
+ final EntityDelta entity = EntityDelta.fromBefore(before);
+ state.add(entity);
+ }
+ return state;
+ }
+
+ /**
* Merge the "after" values from the given {@link EntitySet}, discarding any
* previous "after" states. This is typically used when re-parenting user
* edits onto an updated {@link EntitySet}.
diff --git a/src/com/android/contacts/views/editor/ContactEditorFragment.java b/src/com/android/contacts/views/editor/ContactEditorFragment.java
index e50994a..5b281fc 100644
--- a/src/com/android/contacts/views/editor/ContactEditorFragment.java
+++ b/src/com/android/contacts/views/editor/ContactEditorFragment.java
@@ -33,6 +33,7 @@
import com.android.contacts.ui.widget.PhotoEditorView;
import com.android.contacts.util.EmptyService;
import com.android.contacts.util.WeakAsyncTask;
+import com.android.contacts.views.ContactLoader;
import android.accounts.Account;
import android.app.Activity;
@@ -98,7 +99,7 @@
//TODO Cleanup the load function. It can currenlty also do insert, which is awkward
//TODO Watch for background changes...How?
-public class ContactEditorFragment extends LoaderManagingFragment<ContactEditorLoader.Result> {
+public class ContactEditorFragment extends LoaderManagingFragment<ContactLoader.Result> {
private static final String TAG = "ContactEditorFragment";
@@ -244,14 +245,14 @@
}
@Override
- protected Loader<ContactEditorLoader.Result> onCreateLoader(int id, Bundle args) {
- return new ContactEditorLoader(mContext, mUri, mMimeType, mIntentExtras);
+ protected Loader<ContactLoader.Result> onCreateLoader(int id, Bundle args) {
+ return new ContactLoader(mContext, mUri);
}
@Override
- protected void onLoadFinished(Loader<ContactEditorLoader.Result> loader,
- ContactEditorLoader.Result data) {
- if (data == ContactEditorLoader.Result.NOT_FOUND) {
+ protected void onLoadFinished(Loader<ContactLoader.Result> loader,
+ ContactLoader.Result data) {
+ if (data == ContactLoader.Result.NOT_FOUND) {
// Item has been deleted
Log.i(TAG, "No contact found. Closing fragment");
if (mListener != null) mListener.closeBecauseContactNotFound();
@@ -260,8 +261,22 @@
setData(data);
}
- public void setData(ContactEditorLoader.Result data) {
- mState = data.getEntitySet();
+ public void setData(ContactLoader.Result data) {
+ mState = EntitySet.fromIterator(data.getEntities().iterator());
+ // TODO: Merge in Intent parameters can only be done on the first load.
+ // The behaviour for subsequent loads is probably broken, so fix this
+ final boolean hasExtras = mIntentExtras != null && mIntentExtras.size() > 0;
+ final boolean hasState = mState.size() > 0;
+ if (hasExtras && hasState) {
+ // Find source defining the first RawContact found
+ // TODO: Test this. Can we actually always use the first RawContact. This seems wrong
+ final EntityDelta state = mState.get(0);
+ final String accountType = state.getValues().getAsString(RawContacts.ACCOUNT_TYPE);
+ final Sources sources = Sources.getInstance(mContext);
+ final ContactsSource source = sources.getInflatedSource(accountType,
+ ContactsSource.LEVEL_CONSTRAINTS);
+ EntityModifier.parseExtras(mContext, source, state, mIntentExtras);
+ }
bindEditors();
}
diff --git a/src/com/android/contacts/views/editor/ContactEditorLoader.java b/src/com/android/contacts/views/editor/ContactEditorLoader.java
deleted file mode 100644
index 77c03c0..0000000
--- a/src/com/android/contacts/views/editor/ContactEditorLoader.java
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * Copyright (C) 2010 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.contacts.views.editor;
-
-import com.android.contacts.ContactsUtils;
-import com.android.contacts.model.ContactsSource;
-import com.android.contacts.model.EntityDelta;
-import com.android.contacts.model.EntityModifier;
-import com.android.contacts.model.EntitySet;
-import com.android.contacts.model.Sources;
-
-import android.content.ContentResolver;
-import android.content.ContentUris;
-import android.content.Context;
-import android.content.Loader;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.provider.ContactsContract;
-import android.provider.ContactsContract.Contacts;
-import android.provider.ContactsContract.RawContacts;
-
-public class ContactEditorLoader extends Loader<ContactEditorLoader.Result> {
- private static final String TAG = "ContactEditorLoader";
-
- private final Uri mLookupUri;
- private final String mMimeType;
- private Result mContact;
- private boolean mDestroyed;
- private ForceLoadContentObserver mObserver;
- private final Bundle mIntentExtras;
-
- public ContactEditorLoader(Context context, Uri lookupUri, String mimeType,
- Bundle intentExtras) {
- super(context);
- mLookupUri = lookupUri;
- mMimeType = mimeType;
- mIntentExtras = intentExtras;
- }
-
- /**
- * The result of a load operation. Contains all data necessary to display the contact for
- * editing.
- */
- public static class Result {
- /**
- * Singleton instance that represents "No Contact Found"
- */
- public static final Result NOT_FOUND = new Result(null);
-
- private final EntitySet mEntitySet;
-
- private Result(EntitySet entitySet) {
- mEntitySet = entitySet;
- }
-
- public EntitySet getEntitySet() {
- return mEntitySet;
- }
- }
-
- private final class LoadContactTask extends AsyncTask<Void, Void, Result> {
- @Override
- protected Result doInBackground(Void... params) {
- final ContentResolver resolver = getContext().getContentResolver();
- final Uri uriCurrentFormat = ensureIsContactUri(resolver, mLookupUri);
-
- // Handle both legacy and new authorities
-
- final long contactId;
- final String selection = "0";
- if (Contacts.CONTENT_ITEM_TYPE.equals(mMimeType)) {
- // Handle selected aggregate
- contactId = ContentUris.parseId(uriCurrentFormat);
- } else if (RawContacts.CONTENT_ITEM_TYPE.equals(mMimeType)) {
- // Get id of corresponding aggregate
- final long rawContactId = ContentUris.parseId(uriCurrentFormat);
- contactId = ContactsUtils.queryForContactId(resolver, rawContactId);
- } else throw new IllegalStateException();
-
- return new Result(EntitySet.fromQuery(resolver, RawContacts.CONTACT_ID + "=?",
- new String[] { String.valueOf(contactId) }, null));
- }
-
- /**
- * Transforms the given Uri and returns a Lookup-Uri that represents the contact.
- * For legacy contacts, a raw-contact lookup is performed.
- */
- private Uri ensureIsContactUri(final ContentResolver resolver, final Uri uri) {
- if (uri == null) throw new IllegalArgumentException("uri must not be null");
-
- final String authority = uri.getAuthority();
-
- // Current Style Uri?
- if (ContactsContract.AUTHORITY.equals(authority)) {
- final String type = resolver.getType(uri);
- // Contact-Uri? Good, return it
- if (Contacts.CONTENT_ITEM_TYPE.equals(type)) {
- return uri;
- }
-
- // RawContact-Uri? Transform it to ContactUri
- if (RawContacts.CONTENT_ITEM_TYPE.equals(type)) {
- final long rawContactId = ContentUris.parseId(uri);
- return RawContacts.getContactLookupUri(getContext().getContentResolver(),
- ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId));
- }
-
- // Anything else? We don't know what this is
- throw new IllegalArgumentException("uri format is unknown");
- }
-
- // Legacy Style? Convert to RawContact
- final String OBSOLETE_AUTHORITY = "contacts";
- if (OBSOLETE_AUTHORITY.equals(authority)) {
- // Legacy Format. Convert to RawContact-Uri and then lookup the contact
- final long rawContactId = ContentUris.parseId(uri);
- return RawContacts.getContactLookupUri(resolver,
- ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId));
- }
-
- throw new IllegalArgumentException("uri authority is unknown");
- }
-
- @Override
- protected void onPostExecute(Result result) {
- super.onPostExecute(result);
-
- // TODO: This merging of extras is probably wrong on subsequent loads
-
- // Load edit details in background
- final Sources sources = Sources.getInstance(getContext());
-
- // Handle any incoming values that should be inserted
- final boolean hasExtras = mIntentExtras != null && mIntentExtras.size() > 0;
- final boolean hasState = result.getEntitySet().size() > 0;
- if (hasExtras && hasState) {
- // Find source defining the first RawContact found
- final EntityDelta state = result.getEntitySet().get(0);
- final String accountType = state.getValues().getAsString(RawContacts.ACCOUNT_TYPE);
- final ContactsSource source = sources.getInflatedSource(accountType,
- ContactsSource.LEVEL_CONSTRAINTS);
- EntityModifier.parseExtras(getContext(), source, state, mIntentExtras);
- }
-
- // The creator isn't interested in any further updates
- if (mDestroyed) {
- return;
- }
-
- mContact = result;
- if (result != null) {
- if (mObserver == null) {
- mObserver = new ForceLoadContentObserver();
- }
- // TODO: Do we want a content observer here?
-// Log.i(TAG, "Registering content observer for " + mLookupUri);
-// getContext().getContentResolver().registerContentObserver(mLookupUri, true,
-// mObserver);
- deliverResult(result);
- }
- }
- }
-
- @Override
- public void startLoading() {
- if (mContact != null) {
- deliverResult(mContact);
- } else {
- forceLoad();
- }
- }
-
- @Override
- public void forceLoad() {
- LoadContactTask task = new LoadContactTask();
- task.execute((Void[])null);
- }
-
- @Override
- public void stopLoading() {
- mContact = null;
- if (mObserver != null) {
- getContext().getContentResolver().unregisterContentObserver(mObserver);
- }
- }
-
- @Override
- public void destroy() {
- mContact = null;
- mDestroyed = true;
- }
-}
\ No newline at end of file