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

Commit 6cd5b0ab authored by Katherine Kuan's avatar Katherine Kuan
Browse files

Fix viewing legacy and raw contact URI on tablet

Bug: 5220640
Change-Id: I85c748389921bdff2639fff5f7713e00ba7f9f8c
parent c9eafc62
Loading
Loading
Loading
Loading
+3 −42
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.contacts;
import com.android.contacts.model.AccountType;
import com.android.contacts.model.AccountTypeManager;
import com.android.contacts.model.AccountTypeWithDataSet;
import com.android.contacts.util.ContactLoaderUtils;
import com.android.contacts.util.DataStatus;
import com.android.contacts.util.StreamItemEntry;
import com.android.contacts.util.StreamItemPhotoEntry;
@@ -681,7 +682,8 @@ public class ContactLoader extends Loader<ContactLoader.Result> {
        protected Result doInBackground(Void... args) {
            try {
                final ContentResolver resolver = getContext().getContentResolver();
                final Uri uriCurrentFormat = ensureIsContactUri(resolver, mLookupUri);
                final Uri uriCurrentFormat = ContactLoaderUtils.ensureIsContactUri(
                        resolver, mLookupUri);
                Result result = loadContactEntity(resolver, uriCurrentFormat);
                if (!result.isNotFound()) {
                    if (result.isDirectoryEntry()) {
@@ -706,47 +708,6 @@ public class ContactLoader extends Loader<ContactLoader.Result> {
            }
        }

        /**
         * Transforms the given Uri and returns a Lookup-Uri that represents the contact.
         * For legacy contacts, a raw-contact lookup is performed.
         * @param resolver
         */
        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");
        }

        private Result loadContactEntity(ContentResolver resolver, Uri contactUri) {
            Uri entityUri = Uri.withAppendedPath(contactUri, Contacts.Entity.CONTENT_DIRECTORY);
            Cursor cursor = resolver.query(entityUri, ContactQuery.COLUMNS, null, null,
+50 −38
Original line number Diff line number Diff line
@@ -17,10 +17,10 @@ package com.android.contacts.list;

import com.android.common.widget.CompositeCursorAdapter.Partition;
import com.android.contacts.R;
import com.android.contacts.util.ContactLoaderUtils;
import com.android.contacts.widget.AutoScrollListView;

import android.app.Activity;
import android.content.AsyncQueryHandler;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Loader;
@@ -28,6 +28,7 @@ import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@@ -92,50 +93,63 @@ public abstract class ContactBrowseListFragment extends
    private String mPersistentSelectionPrefix = PERSISTENT_SELECTION_PREFIX;

    protected OnContactBrowserActionListener mListener;
    private ContactLookupTask mContactLookupTask;

    /**
     * Refreshes a contact URI: it may have changed as a result of aggregation
     * activity.
     */
    private class ContactUriQueryHandler extends AsyncQueryHandler {
    private final class ContactLookupTask extends AsyncTask<Void, Void, Uri> {

        public ContactUriQueryHandler(ContentResolver cr) {
            super(cr);
        }
        private final Uri mUri;
        private boolean mIsCancelled;

        public void runQuery() {
            startQuery(0, mSelectedContactUri, mSelectedContactUri,
                    new String[] { Contacts._ID, Contacts.LOOKUP_KEY }, null, null, null);
        public ContactLookupTask(Uri uri) {
            mUri = uri;
        }

        @Override
        protected void onQueryComplete(int token, Object cookie, Cursor data) {
            long contactId = 0;
            String lookupKey = null;
            if (data != null) {
                if (data.moveToFirst()) {
                    contactId = data.getLong(0);
                    lookupKey = data.getString(1);
        protected Uri doInBackground(Void... args) {
            Cursor cursor = null;
            try {
                final ContentResolver resolver = getContext().getContentResolver();
                final Uri uriCurrentFormat = ContactLoaderUtils.ensureIsContactUri(resolver, mUri);
                cursor = resolver.query(uriCurrentFormat,
                        new String[] { Contacts._ID, Contacts.LOOKUP_KEY }, null, null, null);

                if (cursor != null && cursor.moveToFirst()) {
                    final long contactId = cursor.getLong(0);
                    final String lookupKey = cursor.getString(1);
                    if (contactId != 0 && !TextUtils.isEmpty(lookupKey)) {
                        return Contacts.getLookupUri(contactId, lookupKey);
                    }
                data.close();
                }

            if (!cookie.equals(mSelectedContactUri)) {
                return;
                Log.e(TAG, "Error: No contact ID or lookup key for contact " + mUri);
                return null;
            } finally {
                if (cursor != null) {
                    cursor.close();
                }
            }
        }

            Uri uri;
            if (contactId != 0 && lookupKey != null) {
                uri = Contacts.getLookupUri(contactId, lookupKey);
            } else {
                uri = null;
        public void cancel() {
            super.cancel(true);
            // Use a flag to keep track of whether the {@link AsyncTask} was cancelled or not in
            // order to ensure onPostExecute() is not executed after the cancel request. The flag is
            // necessary because {@link AsyncTask} still calls onPostExecute() if the cancel request
            // came after the worker thread was finished.
            mIsCancelled = true;
        }

            onContactUriQueryFinished(uri);
        @Override
        protected void onPostExecute(Uri uri) {
            // Make sure the {@link Fragment} is at least still attached to the {@link Activity}
            // before continuing.
            if (mIsCancelled || !isAdded() || uri == null) {
                return;
            }
            mSelectedContactUri = uri;
            onContactUriQueryFinished(mSelectedContactUri);
        }
    }

    private ContactUriQueryHandler mQueryHandler;

    private boolean mDelaySelection;

@@ -158,7 +172,6 @@ public abstract class ContactBrowseListFragment extends
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        mQueryHandler = new ContactUriQueryHandler(activity.getContentResolver());
        mPrefs = PreferenceManager.getDefaultSharedPreferences(activity);
        restoreFilter();
        restoreSelectedUri(false);
@@ -228,12 +241,10 @@ public abstract class ContactBrowseListFragment extends
    }

    protected void refreshSelectedContactUri() {
        if (mQueryHandler == null) {
            return;
        if (mContactLookupTask != null) {
            mContactLookupTask.cancel();
        }

        mQueryHandler.cancelOperation(0);

        if (!isSelectionVisible()) {
            return;
        }
@@ -249,7 +260,8 @@ public abstract class ContactBrowseListFragment extends
                && mSelectedContactDirectoryId != Directory.LOCAL_INVISIBLE) {
            onContactUriQueryFinished(mSelectedContactUri);
        } else {
            mQueryHandler.runQuery();
            mContactLookupTask = new ContactLookupTask(mSelectedContactUri);
            mContactLookupTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[])null);
        }
    }

+78 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * 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.util;

import android.content.ContentResolver;
import android.content.ContentUris;
import android.net.Uri;
import android.provider.Contacts;
import android.provider.ContactsContract;
import android.provider.ContactsContract.RawContacts;

/**
 * Utility methods for the {@link ContactLoader}.
 */
public final class ContactLoaderUtils {

    /** Static helper, not instantiable. */
    private ContactLoaderUtils() {}

    /**
     * Transforms the given Uri and returns a Lookup-Uri that represents the contact.
     * For legacy contacts, a raw-contact lookup is performed. An {@link IllegalArgumentException}
     * can be thrown if the URI is null or the authority is not recognized.
     *
     * Do not call from the UI thread.
     */
    @SuppressWarnings("deprecation")
    public static Uri ensureIsContactUri(final ContentResolver resolver, final Uri uri)
            throws IllegalArgumentException {
        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 (ContactsContract.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(resolver,
                        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.AUTHORITY;
        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");
    }
}