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

Commit e5d3f897 authored by Josh Gargus's avatar Josh Gargus
Browse files

Fix regression; once again we can apply Gallery photo to contact.

The changes to support hi-res photos in Ic0cabaa5 were not applied to
AttachPhotoActivity.  This CL makes the analogous changes, and many other
cleanups besides.

In addition, applying the Gallery photo works even if the AttachPhotoActivity
is killed (eg: when selecting a contact, or when cropping the photo); this
didn't work even before the regression.

The save-contact Intent which invokes the ContactSaveService no longer
needs to specify a callback Activity (it is OK to pass null if you don't
care about getting a callback).

The subclasses of PhotoSelectionHandler have been significantly simplified,
partly by pushing common behavior to the superclass, and also by directly
accessing state in their outer class instead making their own copies.

ContactLoader.Result.getEntityDeltaList() is a new instance method that
replaces more verbose incantations.

New utility class, ContactPhotoUtils.  Helps with compressing Bitmaps, and
generating temp-file names used when saving hi-res photos to a contact.

Bug: 6298601
Change-Id: I2fe90c33c9fa81716f263d82ed80c0d6f63c6a7e
parent 526232e1
Loading
Loading
Loading
Loading
+32 −9
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.model.EntityDeltaList;
import com.android.contacts.util.ContactLoaderUtils;
import com.android.contacts.util.DataStatus;
import com.android.contacts.util.StreamItemEntry;
@@ -71,7 +72,7 @@ import java.util.Set;
 * Loads a single Contact and all it constituent RawContacts.
 */
public class ContactLoader extends AsyncTaskLoader<ContactLoader.Result> {
    private static final String TAG = "ContactLoader";
    private static final String TAG = ContactLoader.class.getSimpleName();

    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);

@@ -312,6 +313,13 @@ public class ContactLoader extends AsyncTaskLoader<ContactLoader.Result> {
            return mRequestedUri;
        }

        /**
         * Instantiate a new EntityDeltaList for this contact.
         */
        public EntityDeltaList createEntityDeltaList() {
            return EntityDeltaList.fromIterator(getEntities().iterator());
        }

        /**
         * Returns the contact ID.
         */
@@ -419,16 +427,31 @@ public class ContactLoader extends AsyncTaskLoader<ContactLoader.Result> {
         *         writable raw-contact, and false otherwise.
         */
        public boolean isWritableContact(final Context context) {
            if (isDirectoryEntry()) return false;
            return getFirstWritableRawContactId(context) != -1;
        }

        /**
         * Return the ID of the first raw-contact in the contact data that belongs to a
         * contact-writable account, or -1 if no such entity exists.
         */
        public long getFirstWritableRawContactId(final Context context) {
            // Directory entries are non-writable
            if (isDirectoryEntry()) return -1;

            // Iterate through raw-contacts; if we find a writable on, return its ID.
            final AccountTypeManager accountTypes = AccountTypeManager.getInstance(context);
            for (Entity rawContact : getEntities()) {
                final ContentValues rawValues = rawContact.getEntityValues();
                final String accountType = rawValues.getAsString(RawContacts.ACCOUNT_TYPE);
                final String dataSet = rawValues.getAsString(RawContacts.DATA_SET);
                final AccountType type = accountTypes.getAccountType(accountType, dataSet);
                if (type != null && type.areContactsWritable()) return true;
            }
            return false;
            for (Entity entity : getEntities()) {
                ContentValues values = entity.getEntityValues();
                String type = values.getAsString(RawContacts.ACCOUNT_TYPE);
                String dataSet = values.getAsString(RawContacts.DATA_SET);

                AccountType accountType = accountTypes.getAccountType(type, dataSet);
                if (accountType != null && accountType.areContactsWritable()) {
                    return values.getAsLong(RawContacts._ID);
                }
            }
            // No writable raw-contact was found.
            return -1;
        }

        public int getDirectoryExportSupport() {
+30 −25
Original line number Diff line number Diff line
@@ -222,7 +222,7 @@ public class ContactSaveService extends IntentService {
     */
    public static Intent createNewRawContactIntent(Context context,
            ArrayList<ContentValues> values, AccountWithDataSet account,
            Class<?> callbackActivity, String callbackAction) {
            Class<? extends Activity> callbackActivity, String callbackAction) {
        Intent serviceIntent = new Intent(
                context, ContactSaveService.class);
        serviceIntent.setAction(ContactSaveService.ACTION_NEW_RAW_CONTACT);
@@ -290,8 +290,9 @@ public class ContactSaveService extends IntentService {
     * @param updatedPhotoPath denotes a temporary file containing the contact's new photo.
     */
    public static Intent createSaveContactIntent(Context context, EntityDeltaList state,
            String saveModeExtraKey, int saveMode, boolean isProfile, Class<?> callbackActivity,
            String callbackAction, long rawContactId, String updatedPhotoPath) {
            String saveModeExtraKey, int saveMode, boolean isProfile,
            Class<? extends Activity> callbackActivity, String callbackAction, long rawContactId,
            String updatedPhotoPath) {
        Bundle bundle = new Bundle();
        bundle.putString(String.valueOf(rawContactId), updatedPhotoPath);
        return createSaveContactIntent(context, state, saveModeExtraKey, saveMode, isProfile,
@@ -306,8 +307,9 @@ public class ContactSaveService extends IntentService {
     * @param updatedPhotos maps each raw-contact's ID to the file-path of the new photo.
     */
    public static Intent createSaveContactIntent(Context context, EntityDeltaList state,
            String saveModeExtraKey, int saveMode, boolean isProfile, Class<?> callbackActivity,
            String callbackAction, Bundle updatedPhotos) {
            String saveModeExtraKey, int saveMode, boolean isProfile,
            Class<? extends Activity> callbackActivity, String callbackAction,
            Bundle updatedPhotos) {
        Intent serviceIntent = new Intent(
                context, ContactSaveService.class);
        serviceIntent.setAction(ContactSaveService.ACTION_SAVE_CONTACT);
@@ -317,6 +319,7 @@ public class ContactSaveService extends IntentService {
            serviceIntent.putExtra(EXTRA_UPDATED_PHOTOS, (Parcelable) updatedPhotos);
        }

        if (callbackActivity != null) {
            // Callback intent will be invoked by the service once the contact is
            // saved.  The service will put the URI of the new contact as "data" on
            // the callback intent.
@@ -324,12 +327,12 @@ public class ContactSaveService extends IntentService {
            callbackIntent.putExtra(saveModeExtraKey, saveMode);
            callbackIntent.setAction(callbackAction);
            serviceIntent.putExtra(ContactSaveService.EXTRA_CALLBACK_INTENT, callbackIntent);
        }
        return serviceIntent;
    }

    private void saveContact(Intent intent) {
        EntityDeltaList state = intent.getParcelableExtra(EXTRA_CONTACT_STATE);
        Intent callbackIntent = intent.getParcelableExtra(EXTRA_CALLBACK_INTENT);
        boolean isProfile = intent.getBooleanExtra(EXTRA_SAVE_IS_PROFILE, false);
        Bundle updatedPhotos = intent.getParcelableExtra(EXTRA_UPDATED_PHOTOS);

@@ -462,6 +465,8 @@ public class ContactSaveService extends IntentService {
            }
        }

        Intent callbackIntent = intent.getParcelableExtra(EXTRA_CALLBACK_INTENT);
        if (callbackIntent != null) {
            if (succeeded) {
                // Mark the intent to indicate that the save was successful (even if the lookup URI
                // is now null).  For local contacts or the local profile, it's possible that the
@@ -469,9 +474,9 @@ public class ContactSaveService extends IntentService {
                callbackIntent.putExtra(EXTRA_SAVE_SUCCEEDED, true);
            }
            callbackIntent.setData(lookupUri);

            deliverCallback(callbackIntent);
        }
    }

    /**
     * Save updated photo for the specified raw-contact.
@@ -554,7 +559,7 @@ public class ContactSaveService extends IntentService {
     * @param callbackAction is the intent action for the callback intent
     */
    public static Intent createNewGroupIntent(Context context, AccountWithDataSet account,
            String label, long[] rawContactsToAdd, Class<?> callbackActivity,
            String label, long[] rawContactsToAdd, Class<? extends Activity> callbackActivity,
            String callbackAction) {
        Intent serviceIntent = new Intent(context, ContactSaveService.class);
        serviceIntent.setAction(ContactSaveService.ACTION_CREATE_GROUP);
@@ -618,7 +623,7 @@ public class ContactSaveService extends IntentService {
     * Creates an intent that can be sent to this service to rename a group.
     */
    public static Intent createGroupRenameIntent(Context context, long groupId, String newLabel,
            Class<?> callbackActivity, String callbackAction) {
            Class<? extends Activity> callbackActivity, String callbackAction) {
        Intent serviceIntent = new Intent(context, ContactSaveService.class);
        serviceIntent.setAction(ContactSaveService.ACTION_RENAME_GROUP);
        serviceIntent.putExtra(ContactSaveService.EXTRA_GROUP_ID, groupId);
@@ -689,7 +694,7 @@ public class ContactSaveService extends IntentService {
     */
    public static Intent createGroupUpdateIntent(Context context, long groupId, String newLabel,
            long[] rawContactsToAdd, long[] rawContactsToRemove,
            Class<?> callbackActivity, String callbackAction) {
            Class<? extends Activity> callbackActivity, String callbackAction) {
        Intent serviceIntent = new Intent(context, ContactSaveService.class);
        serviceIntent.setAction(ContactSaveService.ACTION_UPDATE_GROUP);
        serviceIntent.putExtra(ContactSaveService.EXTRA_GROUP_ID, groupId);
@@ -959,7 +964,7 @@ public class ContactSaveService extends IntentService {
     */
    public static Intent createJoinContactsIntent(Context context, long contactId1,
            long contactId2, boolean contactWritable,
            Class<?> callbackActivity, String callbackAction) {
            Class<? extends Activity> callbackActivity, String callbackAction) {
        Intent serviceIntent = new Intent(context, ContactSaveService.class);
        serviceIntent.setAction(ContactSaveService.ACTION_JOIN_CONTACTS);
        serviceIntent.putExtra(ContactSaveService.EXTRA_CONTACT_ID1, contactId1);
+102 −164
Original line number Diff line number Diff line
@@ -18,29 +18,31 @@ package com.android.contacts.activities;

import com.android.contacts.ContactsActivity;
import com.android.contacts.R;
import com.android.contacts.model.ExchangeAccountType;
import com.android.contacts.model.GoogleAccountType;
import com.android.contacts.model.AccountType;
import com.android.contacts.model.EntityDelta;
import com.android.contacts.model.EntityDeltaList;
import com.android.contacts.model.EntityModifier;
import com.android.contacts.util.ContactPhotoUtils;
import com.android.contacts.ContactLoader;
import com.android.contacts.ContactSaveService;
import com.android.contacts.ContactsUtils;

import android.content.ContentProviderOperation;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Intent;
import android.content.OperationApplicationException;
import android.content.Loader;
import android.content.Loader.OnLoadCompleteListener;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.os.RemoteException;
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.Photo;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.DisplayPhoto;
import android.provider.ContactsContract.RawContacts;
import android.widget.Toast;
import android.provider.MediaStore;
import android.util.Log;

import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.io.File;

/**
 * Provides an external interface for other applications to attach images
@@ -49,25 +51,38 @@ import java.util.ArrayList;
 * size and give the user a chance to use the face detector.
 */
public class AttachPhotoActivity extends ContactsActivity {
    private static final String TAG = AttachPhotoActivity.class.getSimpleName();

    private static final int REQUEST_PICK_CONTACT = 1;
    private static final int REQUEST_CROP_PHOTO = 2;

    private static final String RAW_CONTACT_URIS_KEY = "raw_contact_uris";
    private static final String KEY_CONTACT_URI = "contact_uri";
    private static final String KEY_TEMP_PHOTO_URI = "temp_photo_uri";

    private Long[] mRawContactIds;
    private File mTempPhotoFile;
    private Uri mTempPhotoUri;

    private ContentResolver mContentResolver;

    // Height/width (in pixels) to request for the photo - queried from the provider.
    // Height and width (in pixels) to request for the photo - queried from the provider.
    private static int mPhotoDim;

    private Uri mContactUri;

    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);

        if (icicle != null) {
            mRawContactIds = toClassArray(icicle.getLongArray(RAW_CONTACT_URIS_KEY));
            final String uri = icicle.getString(KEY_CONTACT_URI);
            mContactUri = (uri == null) ? null : Uri.parse(uri);

            mTempPhotoUri = Uri.parse(icicle.getString(KEY_TEMP_PHOTO_URI));
            mTempPhotoFile = new File(mTempPhotoUri.getPath());
        } else {
            mTempPhotoFile = ContactPhotoUtils.generateTempPhotoFile();
            mTempPhotoUri = Uri.fromFile(mTempPhotoFile);

            Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
            intent.setType(Contacts.CONTENT_ITEM_TYPE);
            startActivityForResult(intent, REQUEST_PICK_CONTACT);
@@ -89,32 +104,8 @@ public class AttachPhotoActivity extends ContactsActivity {
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);

        if (mRawContactIds != null && mRawContactIds.length != 0) {
            outState.putLongArray(RAW_CONTACT_URIS_KEY, toPrimativeArray(mRawContactIds));
        }
    }

    private static long[] toPrimativeArray(Long[] in) {
        if (in == null) {
            return null;
        }
        long[] out = new long[in.length];
        for (int i = 0; i < in.length; i++) {
            out[i] = in[i];
        }
        return out;
    }

    private static Long[] toClassArray(long[] in) {
        if (in == null) {
            return null;
        }
        Long[] out = new Long[in.length];
        for (int i = 0; i < in.length; i++) {
            out[i] = in[i];
        }
        return out;
        if (mContactUri != null) outState.putString(KEY_CONTACT_URI, mContactUri.toString());
        outState.putString(KEY_TEMP_PHOTO_URI, mTempPhotoUri.toString());
    }

    @Override
@@ -137,147 +128,94 @@ public class AttachPhotoActivity extends ContactsActivity {
            intent.putExtra("aspectY", 1);
            intent.putExtra("outputX", mPhotoDim);
            intent.putExtra("outputY", mPhotoDim);
            intent.putExtra("return-data", true);
            intent.putExtra(MediaStore.EXTRA_OUTPUT, mTempPhotoUri);

            startActivityForResult(intent, REQUEST_CROP_PHOTO);

            // while they're cropping, convert the contact into a raw_contact
            final long contactId = ContentUris.parseId(result.getData());
            final ArrayList<Long> rawContactIdsList = queryForAllRawContactIds(
                    mContentResolver, contactId);
            mRawContactIds = new Long[rawContactIdsList.size()];
            mRawContactIds = rawContactIdsList.toArray(mRawContactIds);
            mContactUri = result.getData();

            if (mRawContactIds == null || rawContactIdsList.isEmpty()) {
                Toast.makeText(this, R.string.contactSavedErrorToast, Toast.LENGTH_LONG).show();
            }
        } else if (requestCode == REQUEST_CROP_PHOTO) {
            final Bundle extras = result.getExtras();
            if (extras != null && mRawContactIds != null) {
                Bitmap photo = extras.getParcelable("data");
                if (photo != null) {
                    ByteArrayOutputStream stream = new ByteArrayOutputStream();
                    photo.compress(Bitmap.CompressFormat.PNG, 100, stream);

                    final ContentValues imageValues = new ContentValues();
                    imageValues.put(Photo.PHOTO, stream.toByteArray());
                    imageValues.put(RawContacts.Data.IS_SUPER_PRIMARY, 1);

                    // attach the photo to every raw contact
                    for (Long rawContactId : mRawContactIds) {

                        // exchange and google only allow one image, so do an update rather than insert
                        boolean shouldUpdate = false;

                        final Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI,
                                rawContactId);
                        final Uri rawContactDataUri = Uri.withAppendedPath(rawContactUri,
                                RawContacts.Data.CONTENT_DIRECTORY);
                        insertPhoto(imageValues, rawContactDataUri, true);
                    }
                }
            loadContact(mContactUri, new ContactLoader.Listener() {
                @Override
                public void onContactLoaded(ContactLoader.Result contact) {
                    saveContact(contact);
                }
            finish();
            });
        }
    }

    // TODO: move to background
    public static ArrayList<Long> queryForAllRawContactIds(ContentResolver cr, long contactId) {
        Cursor rawContactIdCursor = null;
        ArrayList<Long> rawContactIds = new ArrayList<Long>();
    // TODO: consider moving this to ContactLoader, especially if we keep adding similar
    // code elsewhere (ViewNotificationService is another case).  The only concern is that,
    // although this is convenient, it isn't quite as robust as using LoaderManager... for
    // instance, the loader doesn't persist across Activity restarts.
    private void loadContact(Uri contactUri, final ContactLoader.Listener listener) {
        final ContactLoader loader = new ContactLoader(this, contactUri);
        loader.registerListener(0, new OnLoadCompleteListener<ContactLoader.Result>() {
            @Override
            public void onLoadComplete(
                    Loader<ContactLoader.Result> loader, ContactLoader.Result contact) {
                try {
            rawContactIdCursor = cr.query(RawContacts.CONTENT_URI,
                    new String[] {RawContacts._ID},
                    RawContacts.CONTACT_ID + "=" + contactId, null, null);
            if (rawContactIdCursor != null) {
                while (rawContactIdCursor.moveToNext()) {
                    rawContactIds.add(rawContactIdCursor.getLong(0));
                }
                    loader.reset();
                }
        } finally {
            if (rawContactIdCursor != null) {
                rawContactIdCursor.close();
                catch (RuntimeException e) {
                    Log.e(TAG, "Error resetting loader", e);
                }
                listener.onContactLoaded(contact);
            }
        return rawContactIds;
        });
        loader.startLoading();
    }

    /**
     * Inserts a photo on the raw contact.
     * @param values the photo values
     * @param assertAccount if true, will check to verify that no photos exist for Google,
     *     Exchange and unsynced phone account types. These account types only take one picture,
     *     so if one exists, the account will be updated with the new photo.
     * If prerequisites have been met, attach the photo to a raw-contact and save.
     * The prerequisites are:
     * - photo has been cropped
     * - contact has been loaded
     */
    private void insertPhoto(ContentValues values, Uri rawContactDataUri,
            boolean assertAccount) {

        ArrayList<ContentProviderOperation> operations =
            new ArrayList<ContentProviderOperation>();
    private void saveContact(ContactLoader.Result contact) {

        if (assertAccount) {
            // Make sure no pictures exist for Google, Exchange and unsynced phone accounts.
            operations.add(ContentProviderOperation.newAssertQuery(rawContactDataUri)
                    .withSelection(Photo.MIMETYPE + "=? AND "
                            + RawContacts.DATA_SET + " IS NULL AND ("
                            + RawContacts.ACCOUNT_TYPE + " IN (?,?) OR "
                            + RawContacts.ACCOUNT_TYPE + " IS NULL)",
                            new String[] {Photo.CONTENT_ITEM_TYPE, GoogleAccountType.ACCOUNT_TYPE,
                            ExchangeAccountType.ACCOUNT_TYPE})
                            .withExpectedCount(0).build());
        // Obtain the raw-contact that we will save to.
        EntityDeltaList deltaList = contact.createEntityDeltaList();
        EntityDelta raw = deltaList.getFirstWritableRawContact(this);
        if (raw == null) {
            Log.w(TAG, "no writable raw-contact found");
            return;
        }

        // insert the photo
        values.put(Photo.MIMETYPE, Photo.CONTENT_ITEM_TYPE);
        operations.add(ContentProviderOperation.newInsert(rawContactDataUri)
                .withValues(values).build());

        try {
            mContentResolver.applyBatch(ContactsContract.AUTHORITY, operations);
        } catch (RemoteException e) {
            throw new IllegalStateException("Problem querying raw_contacts/data", e);
        } catch (OperationApplicationException e) {
            // the account doesn't allow multiple photos, so update
            if (assertAccount) {
                updatePhoto(values, rawContactDataUri, false);
            } else {
                throw new IllegalStateException("Problem inserting photo into raw_contacts/data", e);
            }
        }
        // Create a scaled, compressed bitmap to add to the entity-delta list.
        final int size = ContactsUtils.getThumbnailSize(this);
        final Bitmap bitmap = BitmapFactory.decodeFile(mTempPhotoFile.getAbsolutePath());
        final Bitmap scaled = Bitmap.createScaledBitmap(bitmap, size, size, false);
        final byte[] compressed = ContactPhotoUtils.compressBitmap(scaled);
        if (compressed == null) {
            Log.w(TAG, "could not create scaled and compressed Bitmap");
            return;
        }

    /**
     * Tries to update the photo on the raw_contact.  If no photo exists, and allowInsert == true,
     * then will try to {@link #updatePhoto(ContentValues, boolean)}
     */
    private void updatePhoto(ContentValues values, Uri rawContactDataUri,
            boolean allowInsert) {
        ArrayList<ContentProviderOperation> operations =
            new ArrayList<ContentProviderOperation>();

        values.remove(Photo.MIMETYPE);

        // check that a photo exists
        operations.add(ContentProviderOperation.newAssertQuery(rawContactDataUri)
                .withSelection(Photo.MIMETYPE + "=?", new String[] {
                    Photo.CONTENT_ITEM_TYPE
                }).withExpectedCount(1).build());

        // update that photo
        operations.add(ContentProviderOperation.newUpdate(rawContactDataUri)
                .withSelection(Photo.MIMETYPE + "=?", new String[] {Photo.CONTENT_ITEM_TYPE})
                .withValues(values).build());

        try {
            mContentResolver.applyBatch(ContactsContract.AUTHORITY, operations);
        } catch (RemoteException e) {
            throw new IllegalStateException("Problem querying raw_contacts/data", e);
        } catch (OperationApplicationException e) {
            if (allowInsert) {
                // they deleted the photo between insert and update, so insert one
                insertPhoto(values, rawContactDataUri, false);
            } else {
                throw new IllegalStateException("Problem inserting photo raw_contacts/data", e);
            }
        // Add compressed bitmap to entity-delta... this allows us to save to
        // a new contact; otherwise the entity-delta-list would be empty, and
        // the ContactSaveService would not create the new contact, and the
        // full-res photo would fail to be saved to the non-existent contact.
        AccountType account = raw.getRawContactAccountType(this);
        EntityDelta.ValuesDelta values =
                EntityModifier.ensureKindExists(raw, account, Photo.CONTENT_ITEM_TYPE);
        if (values == null) {
            Log.w(TAG, "cannot attach photo to this account type");
            return;
        }
        values.put(Photo.PHOTO, compressed);

        // Finally, invoke the ContactSaveService.
        Log.v(TAG, "all prerequisites met, about to save photo to contact");
        Intent intent = ContactSaveService.createSaveContactIntent(
                this,
                deltaList,
                "", 0,
                contact.isUserProfile(),
                null, null,
                raw.getRawContactId(),
                mTempPhotoFile.getAbsolutePath());
        startService(intent);
        finish();
    }
}
+4 −13
Original line number Diff line number Diff line
@@ -560,19 +560,10 @@ public class ConfirmAddDetailActivity extends Activity implements
    }

    public void findEditableRawContact() {
        if (mEntityDeltaList == null) {
            return;
        }
        for (EntityDelta state : mEntityDeltaList) {
            final String accountType = state.getValues().getAsString(RawContacts.ACCOUNT_TYPE);
            final String dataSet = state.getValues().getAsString(RawContacts.DATA_SET);
            final AccountType type = mAccountTypeManager.getAccountType(accountType, dataSet);

            if (type.areContactsWritable()) {
                mEditableAccountType = type;
                mState = state;
                return;
            }
        if (mEntityDeltaList == null) return;
        mState = mEntityDeltaList.getFirstWritableRawContact(this);
        if (mState != null) {
            mEditableAccountType = mState.getRawContactAccountType(this);
        }
    }

+20 −29

File changed.

Preview size limit exceeded, changes collapsed.

Loading