Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a84cf927 authored by Makoto Onuki's avatar Makoto Onuki
Browse files

Tiny clean up for ConfirmAddDetailActivity

Also improved EntityDelta/EntityDeltaList.toString() and added a log
to buildDiff().

Change-Id: I1585467a0396cc6b1b6d5746ee8c02e217cc420a
parent f471a82d
Loading
Loading
Loading
Loading
+57 −62
Original line number Diff line number Diff line
@@ -78,17 +78,16 @@ import java.util.HashMap;
 * This is a dialog-themed activity for confirming the addition of a detail to an existing contact
 * (once the user has selected this contact from a list of all contacts). The incoming intent
 * must have an extra with max 1 phone or email specified, using
 * {@link ContactsContract.Intents.Insert.PHONE} with type
 * {@link ContactsContract.Intents.Insert.PHONE_TYPE} or
 * {@link ContactsContract.Intents.Insert.EMAIL} with type
 * {@link ContactsContract.Intents.Insert.EMAIL_TYPE} intent keys.
 * {@link android.provider.ContactsContract.Intents.Insert#PHONE} with type
 * {@link android.provider.ContactsContract.Intents.Insert#PHONE_TYPE} or
 * {@link android.provider.ContactsContract.Intents.Insert#EMAIL} with type
 * {@link android.provider.ContactsContract.Intents.Insert#EMAIL_TYPE} intent keys.
 */
public class ConfirmAddDetailActivity extends Activity implements
        DialogManager.DialogShowingViewActivity {

    private static final String TAG = ConfirmAddDetailActivity.class.getSimpleName();

    private static final String LEGACY_CONTACTS_AUTHORITY = "contacts";
    private static final String TAG = "ConfirmAdd"; // The class name is too long to be a tag.
    private static final boolean VERBOSE_LOGGING = Log.isLoggable(TAG, Log.VERBOSE);

    private LayoutInflater mInflater;
    private View mRootView;
@@ -102,15 +101,19 @@ public class ConfirmAddDetailActivity extends Activity implements
    private ContentResolver mContentResolver;

    private AccountType mEditableAccountType;
    private EntityDelta mState;
    private Uri mContactUri;
    private long mContactId;
    private String mDisplayName;
    private boolean mIsReadyOnly;
    private boolean mIsReadOnly;

    private QueryHandler mQueryHandler;

    /** {@link EntityDeltaList} for the entire selected contact. */
    private EntityDeltaList mEntityDeltaList;

    /** {@link EntityDeltaList} for the editable account */
    private EntityDelta mEntityDelta;

    private String mMimetype = Phone.CONTENT_ITEM_TYPE;

    /**
@@ -168,9 +171,9 @@ public class ConfirmAddDetailActivity extends Activity implements
     * a disambiguation case. For example, if the contact does not have a
     * nickname, use the email field, and etc.
     */
    private static final String[] sMimeTypePriorityList = new String[] { Nickname.CONTENT_ITEM_TYPE,
            Email.CONTENT_ITEM_TYPE, Im.CONTENT_ITEM_TYPE, StructuredPostal.CONTENT_ITEM_TYPE,
            Phone.CONTENT_ITEM_TYPE };
    private static final String[] MIME_TYPE_PRIORITY_LIST = new String[] {
            Nickname.CONTENT_ITEM_TYPE, Email.CONTENT_ITEM_TYPE, Im.CONTENT_ITEM_TYPE,
            StructuredPostal.CONTENT_ITEM_TYPE, Phone.CONTENT_ITEM_TYPE };

    private static final int TOKEN_CONTACT_INFO = 0;
    private static final int TOKEN_PHOTO_QUERY = 1;
@@ -180,7 +183,7 @@ public class ConfirmAddDetailActivity extends Activity implements
    private final OnClickListener mDetailsButtonClickListener = new OnClickListener() {
        @Override
        public void onClick(View v) {
            if (mIsReadyOnly) {
            if (mIsReadOnly) {
                onSaveCompleted(true);
            } else {
                doSaveAction();
@@ -250,7 +253,8 @@ public class ConfirmAddDetailActivity extends Activity implements
        mPhotoView = (ImageView) findViewById(R.id.photo);
        mEditorContainerView = (ViewGroup) findViewById(R.id.editor_container);

        startContactQuery(mContactUri, true);
        resetAsyncQueryHandler();
        startContactQuery(mContactUri);

        new QueryEntitiesTask(this).execute(intent);
    }
@@ -282,13 +286,8 @@ public class ConfirmAddDetailActivity extends Activity implements
     * Internal method to query contact by Uri.
     *
     * @param contactUri the contact uri
     * @param resetQueryHandler whether to use a new AsyncQueryHandler or not
     */
    private void startContactQuery(Uri contactUri, boolean resetQueryHandler) {
        if (resetQueryHandler) {
            resetAsyncQueryHandler();
        }

    private void startContactQuery(Uri contactUri) {
        mQueryHandler.startQuery(TOKEN_CONTACT_INFO, contactUri, contactUri, ContactQuery.COLUMNS,
                null, null, null);
    }
@@ -298,13 +297,8 @@ public class ConfirmAddDetailActivity extends Activity implements
     *
     * @param photoId the photo id.
     * @param lookupKey the lookup uri.
     * @param resetQueryHandler whether to use a new AsyncQueryHandler or not.
     */
    private void startPhotoQuery(long photoId, Uri lookupKey, boolean resetQueryHandler) {
        if (resetQueryHandler) {
            resetAsyncQueryHandler();
        }

    private void startPhotoQuery(long photoId, Uri lookupKey) {
        mQueryHandler.startQuery(TOKEN_PHOTO_QUERY, lookupKey,
                ContentUris.withAppendedId(Data.CONTENT_URI, photoId),
                PhotoQuery.COLUMNS, null, null, null);
@@ -420,9 +414,6 @@ public class ConfirmAddDetailActivity extends Activity implements
                return;
            }
            activityTarget.setEntityDeltaList(entityList);
            activityTarget.findEditableRawContact();
            activityTarget.parseExtras();
            activityTarget.bindEditor();
        }
    }

@@ -477,12 +468,11 @@ public class ConfirmAddDetailActivity extends Activity implements
                                // Otherwise do the photo query.
                                Uri lookupUri = Contacts.getLookupUri(mContactId,
                                        cursor.getString(ContactQuery.LOOKUP_KEY));
                                startPhotoQuery(photoId, lookupUri,
                                        false /* don't reset query handler */);
                                startPhotoQuery(photoId, lookupUri);
                                // Display the name because there is no
                                // disambiguation query.
                                setDisplayName();
                                onLoadDataFinished();
                                showDialogContent();
                            }
                        }
                        break;
@@ -500,7 +490,7 @@ public class ConfirmAddDetailActivity extends Activity implements
                            // If there are no other contacts with this name,
                            // then display the name.
                            setDisplayName();
                            onLoadDataFinished();
                            showDialogContent();
                        }
                        break;
                    }
@@ -535,14 +525,14 @@ public class ConfirmAddDetailActivity extends Activity implements
                            // Find the first non-empty field according to the
                            // mimetype priority list and display this under the
                            // contact's display name to disambiguate the contact.
                            for (String mimeType : sMimeTypePriorityList) {
                            for (String mimeType : MIME_TYPE_PRIORITY_LIST) {
                                if (hashMapCursorData.containsKey(mimeType)) {
                                    setDisplayName();
                                    setExtraInfoField(hashMapCursorData.get(mimeType));
                                    break;
                                }
                            }
                            onLoadDataFinished();
                            showDialogContent();
                        }
                        break;
                    }
@@ -555,28 +545,35 @@ public class ConfirmAddDetailActivity extends Activity implements
        }
    }

    public void setEntityDeltaList(EntityDeltaList entityList) {
        mEntityDeltaList = entityList;
    }

    public void findEditableRawContact() {
        if (mEntityDeltaList == null) return;
        mState = mEntityDeltaList.getFirstWritableRawContact(this);
        if (mState != null) {
            mEditableAccountType = mState.getRawContactAccountType(this);
    private void setEntityDeltaList(EntityDeltaList entityList) {
        if (entityList == null) {
            throw new IllegalStateException();
        }
        if (VERBOSE_LOGGING) {
            Log.v(TAG, "setEntityDeltaList: " + entityList);
        }

    public void parseExtras() {
        if (mEditableAccountType == null || mState == null) {
            return;
        }
        mEntityDeltaList = entityList;

        // Find the editable type.
        mEntityDelta = mEntityDeltaList.getFirstWritableRawContact(this);
        if (mEntityDelta == null) {
            mIsReadOnly = true;
            mEditableAccountType = null;
        } else {
            mIsReadOnly = false;

            mEditableAccountType = mEntityDelta.getRawContactAccountType(this);

            // Handle any incoming values that should be inserted
            final Bundle extras = getIntent().getExtras();
            if (extras != null && extras.size() > 0) {
                // If there are any intent extras, add them as additional fields in the EntityDelta.
            EntityModifier.parseExtras(this, mEditableAccountType, mState, extras);
                EntityModifier.parseExtras(this, mEditableAccountType, mEntityDelta, extras);
            }
        }

        bindEditor();
    }

    /**
@@ -584,19 +581,18 @@ public class ConfirmAddDetailActivity extends Activity implements
     */
    private void bindEditor() {
        if (mEntityDeltaList == null) {
            return;
            throw new IllegalStateException();
        }

        // If no valid raw contact (to insert the data) was found, we won't have an editable
        // account type to use. In this case, display an error message and hide the "OK" button.
        if (mEditableAccountType == null) {
            mIsReadyOnly = true;
        if (mIsReadOnly) {
            mReadOnlyWarningView.setText(getString(R.string.contact_read_only));
            mReadOnlyWarningView.setVisibility(View.VISIBLE);
            mEditorContainerView.setVisibility(View.GONE);
            findViewById(R.id.btn_done).setVisibility(View.GONE);
            // Nothing more to be done, just show the UI
            onLoadDataFinished();
            showDialogContent();
            return;
        }

@@ -605,11 +601,11 @@ public class ConfirmAddDetailActivity extends Activity implements
            // Skip kind that are not editable
            if (!kind.editable) continue;
            if (mMimetype.equals(kind.mimeType)) {
                for (ValuesDelta valuesDelta : mState.getMimeEntries(mMimetype)) {
                for (ValuesDelta valuesDelta : mEntityDelta.getMimeEntries(mMimetype)) {
                    // Skip entries that aren't visible
                    if (!valuesDelta.isVisible()) continue;
                    if (valuesDelta.isInsert()) {
                        inflateEditorView(kind, valuesDelta, mState);
                        inflateEditorView(kind, valuesDelta, mEntityDelta);
                        return;
                    }
                }
@@ -660,7 +656,7 @@ public class ConfirmAddDetailActivity extends Activity implements
     * once all the queries have completed, otherwise the screen will flash as additional data
     * comes in.
     */
    private void onLoadDataFinished() {
    private void showDialogContent() {
        mRootView.setVisibility(View.VISIBLE);
    }

@@ -673,14 +669,13 @@ public class ConfirmAddDetailActivity extends Activity implements
        task.execute(mEntityDeltaList);
    }


    /**
     * Background task for persisting edited contact data, using the changes
     * defined by a set of {@link EntityDelta}. This task starts
     * {@link EmptyService} to make sure the background thread can finish
     * persisting in cases where the system wants to reclaim our process.
     */
    public static class PersistTask extends AsyncTask<EntityDeltaList, Void, Integer> {
    private static class PersistTask extends AsyncTask<EntityDeltaList, Void, Integer> {
        // In the future, use ContactSaver instead of WeakAsyncTask because of
        // the danger of the activity being null during a save action
        private static final int PERSIST_TRIES = 3;
+11 −3
Original line number Diff line number Diff line
@@ -78,7 +78,7 @@ public class EntityDelta implements Parcelable {
     * Internal map of children values from {@link Entity#getSubValues()}, which
     * we store here sorted into {@link Data#MIMETYPE} bins.
     */
    private HashMap<String, ArrayList<ValuesDelta>> mEntries = Maps.newHashMap();
    private final HashMap<String, ArrayList<ValuesDelta>> mEntries = Maps.newHashMap();

    public EntityDelta() {
    }
@@ -354,15 +354,18 @@ public class EntityDelta implements Parcelable {
    public String toString() {
        final StringBuilder builder = new StringBuilder();
        builder.append("\n(");
        builder.append("Uri=");
        builder.append(mContactsQueryUri);
        builder.append(", Values=");
        builder.append(mValues != null ? mValues.toString() : "null");
        builder.append(") = {");
        builder.append(", Entries={");
        for (ArrayList<ValuesDelta> mimeEntries : mEntries.values()) {
            for (ValuesDelta child : mimeEntries) {
                builder.append("\n\t");
                child.toString(builder);
            }
        }
        builder.append("\n}\n");
        builder.append("\n})\n");
        return builder.toString();
    }

@@ -865,6 +868,11 @@ public class EntityDelta implements Parcelable {
         */
        public void toString(StringBuilder builder) {
            builder.append("{ ");
            builder.append("IdColumn=");
            builder.append(mIdColumn);
            builder.append(", FromTemplate=");
            builder.append(mFromTemplate);
            builder.append(", ");
            for (String key : this.keySet()) {
                builder.append(key);
                builder.append("=");
+40 −6
Original line number Diff line number Diff line
@@ -16,24 +16,25 @@

package com.android.contacts.model;

import com.android.contacts.model.EntityDelta.ValuesDelta;
import com.google.android.collect.Lists;

import android.content.ContentProviderOperation;
import android.content.ContentProviderOperation.Builder;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Entity;
import android.content.EntityIterator;
import android.content.ContentProviderOperation.Builder;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
import android.provider.ContactsContract.AggregationExceptions;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.RawContacts;

import com.google.android.collect.Lists;

import com.android.contacts.model.EntityDelta.ValuesDelta;
import android.util.Log;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;

/**
@@ -42,6 +43,9 @@ import java.util.Iterator;
 * and applying another {@link EntityDeltaList} over it.
 */
public class EntityDeltaList extends ArrayList<EntityDelta> implements Parcelable {
    private static final String TAG = "EntityDeltaList";
    private static final boolean VERBOSE_LOGGING = Log.isLoggable(TAG, Log.VERBOSE);

    private boolean mSplitRawContacts;
    private long[] mJoinWithRawContactIds;

@@ -123,6 +127,9 @@ public class EntityDeltaList extends ArrayList<EntityDelta> implements Parcelabl
     * any {@link AggregationExceptions} rules needed to groups edits together.
     */
    public ArrayList<ContentProviderOperation> buildDiff() {
        if (VERBOSE_LOGGING) {
            Log.v(TAG, "buildDiff: list=" + toString());
        }
        final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();

        final long rawContactId = this.findRawContactId();
@@ -197,10 +204,23 @@ public class EntityDeltaList extends ArrayList<EntityDelta> implements Parcelabl
        if (diff.size() == assertMark) {
            diff.clear();
        }

        if (VERBOSE_LOGGING) {
            Log.v(TAG, "buildDiff: ops=" + diffToString(diff));
        }
        return diff;
    }

    private static String diffToString(ArrayList<ContentProviderOperation> ops) {
        StringBuilder sb = new StringBuilder();
        sb.append("[\n");
        for (ContentProviderOperation op : ops) {
            sb.append(op.toString());
            sb.append(",\n");
        }
        sb.append("]\n");
        return sb.toString();
    }

    /**
     * Start building a {@link ContentProviderOperation} that will keep two
     * {@link RawContacts} together.
@@ -416,4 +436,18 @@ public class EntityDeltaList extends ArrayList<EntityDelta> implements Parcelabl
            return new EntityDeltaList[size];
        }
    };

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("(");
        sb.append("Split=");
        sb.append(mSplitRawContacts);
        sb.append(", Join=[");
        sb.append(Arrays.toString(mJoinWithRawContactIds));
        sb.append("], Values=");
        sb.append(super.toString());
        sb.append(")");
        return sb.toString();
    }
}