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

Commit 2d97b5f8 authored by Marcus Hagerott's avatar Marcus Hagerott
Browse files

Allow creation of duplicates of empty system groups

Empty system groups are not shown in the nav drawer so showing an error that
they already exist when a user tries to create them is confusing.

Bug 28718604

Change-Id: I5f96ef862272cc35ad25ac028b785a4ecf07e6e7
parent a4fe1ee4
Loading
Loading
Loading
Loading
+39 −38
Original line number Diff line number Diff line
@@ -25,9 +25,8 @@ import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.Loader;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.provider.ContactsContract.Groups;
import android.support.design.widget.TextInputLayout;
import android.support.v7.app.AlertDialog;
import android.text.Editable;
@@ -273,16 +272,27 @@ public final class GroupNameEditDialogFragment extends DialogFragment implements
    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        // Only a single loader so id is ignored.
        return new CursorLoader(getActivity(), GroupNameQuery.URI,
                GroupNameQuery.PROJECTION, GroupNameQuery.getSelection(mAccount),
                GroupNameQuery.getSelectionArgs(mAccount), null);
        return new CursorLoader(getActivity(), Groups.CONTENT_SUMMARY_URI,
                new String[] { Groups.TITLE, Groups.SYSTEM_ID, Groups.ACCOUNT_TYPE,
                        Groups.SUMMARY_COUNT, Groups.GROUP_IS_READ_ONLY},
                getSelection(), getSelectionArgs(), null);
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
        mExistingGroups = new HashSet<>();
        final GroupUtil.GroupsProjection projection = new GroupUtil.GroupsProjection(data);
        while (data.moveToNext()) {
            mExistingGroups.add(data.getString(GroupNameQuery.TITLE));
            final String title = projection.getTitle(data);
            // Empty system groups aren't shown in the nav drawer so it would be confusing to tell
            // the user that they already exist. Instead we allow them to create a duplicate
            // group in this case. This is how the web handles this case as well (it creates a
            // new non-system group if a new group with a title that matches a system group is
            // create).
            if (projection.isEmptyFFCGroup(data)) {
                continue;
            }
            mExistingGroups.add(title);
        }
    }

@@ -290,38 +300,6 @@ public final class GroupNameEditDialogFragment extends DialogFragment implements
    public void onLoaderReset(Loader<Cursor> loader) {
    }

    /**
     * Defines the structure of the query performed by the CursorLoader created by
     * GroupNameEditDialogFragment
     */
    private static class GroupNameQuery {

        public static final int TITLE = 0;
        public static final Uri URI = ContactsContract.Groups.CONTENT_URI;
        public static final String[] PROJECTION = new String[] { ContactsContract.Groups.TITLE };

        public static String getSelection(AccountWithDataSet account) {
            final StringBuilder builder = new StringBuilder();
            builder.append(ContactsContract.Groups.ACCOUNT_NAME).append("=? AND ")
                    .append(ContactsContract.Groups.ACCOUNT_TYPE).append("=?");
            if (account.dataSet != null) {
                builder.append(" AND ").append(ContactsContract.Groups.DATA_SET).append("=?");
            }
            return builder.toString();
        }

        public static String[] getSelectionArgs(AccountWithDataSet account) {
            final int len = account.dataSet == null ? 2 : 3;
            final String[] args = new String[len];
            args[0] = account.name;
            args[1] = account.type;
            if (account.dataSet != null) {
                args[2] = account.dataSet;
            }
            return args;
        }
    }

    private void showInputMethod(View view) {
        final InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(
                Context.INPUT_METHOD_SERVICE);
@@ -352,4 +330,27 @@ public final class GroupNameEditDialogFragment extends DialogFragment implements
        return mGroupNameEditText == null || mGroupNameEditText.getText() == null
                ? null : mGroupNameEditText.getText().toString();
    }

    private String getSelection() {
        final StringBuilder builder = new StringBuilder();
        builder.append(Groups.ACCOUNT_NAME).append("=? AND ")
               .append(Groups.ACCOUNT_TYPE).append("=? AND ")
               .append(Groups.DELETED).append("=?");
        if (mAccount.dataSet != null) {
            builder.append(" AND ").append(Groups.DATA_SET).append("=?");
        }
        return builder.toString();
    }

    private String[] getSelectionArgs() {
        final int len = mAccount.dataSet == null ? 3 : 4;
        final String[] args = new String[len];
        args[0] = mAccount.name;
        args[1] = mAccount.type;
        args[2] = "0"; // Not deleted
        if (mAccount.dataSet != null) {
            args[3] = mAccount.dataSet;
        }
        return args;
    }
}
+73 −0
Original line number Diff line number Diff line
@@ -219,4 +219,77 @@ public final class GroupUtil {
        }
        return array;
    }

    /**
     * Stores column ordering for the projection of a query of ContactsContract.Groups
     */
    public static final class GroupsProjection {
        public final int groupId;
        public final int title;
        public final int summaryCount;
        public final int systemId;
        public final int accountName;
        public final int accountType;
        public final int dataSet;
        public final int autoAdd;
        public final int favorites;
        public final int isReadOnly;
        public final int deleted;

        public GroupsProjection(Cursor cursor) {
            groupId = cursor.getColumnIndex(Groups._ID);
            title = cursor.getColumnIndex(Groups.TITLE);
            summaryCount = cursor.getColumnIndex(Groups.SUMMARY_COUNT);
            systemId = cursor.getColumnIndex(Groups.SYSTEM_ID);
            accountName = cursor.getColumnIndex(Groups.ACCOUNT_NAME);
            accountType = cursor.getColumnIndex(Groups.ACCOUNT_TYPE);
            dataSet = cursor.getColumnIndex(Groups.DATA_SET);
            autoAdd = cursor.getColumnIndex(Groups.AUTO_ADD);
            favorites = cursor.getColumnIndex(Groups.FAVORITES);
            isReadOnly = cursor.getColumnIndex(Groups.GROUP_IS_READ_ONLY);
            deleted = cursor.getColumnIndex(Groups.DELETED);
        }

        public GroupsProjection(String[] projection) {
            List<String> list = Arrays.asList(projection);
            groupId = list.indexOf(Groups._ID);
            title = list.indexOf(Groups.TITLE);
            summaryCount = list.indexOf(Groups.SUMMARY_COUNT);
            systemId = list.indexOf(Groups.SYSTEM_ID);
            accountName = list.indexOf(Groups.ACCOUNT_NAME);
            accountType = list.indexOf(Groups.ACCOUNT_TYPE);
            dataSet = list.indexOf(Groups.DATA_SET);
            autoAdd = list.indexOf(Groups.AUTO_ADD);
            favorites = list.indexOf(Groups.FAVORITES);
            isReadOnly = list.indexOf(Groups.GROUP_IS_READ_ONLY);
            deleted = list.indexOf(Groups.DELETED);
        }

        public String getTitle(Cursor cursor) {
            return cursor.getString(title);
        }

        public long getId(Cursor cursor) {
            return cursor.getLong(groupId);
        }

        public String getSystemId(Cursor cursor) {
            return cursor.getString(systemId);
        }

        public int getSummaryCount(Cursor cursor) {
            return cursor.getInt(summaryCount);
        }

        public boolean isEmptyFFCGroup(Cursor cursor) {
            if (accountType == -1 || isReadOnly == -1 ||
                    systemId == -1 || summaryCount == -1) {
                throw new IllegalArgumentException("Projection is missing required columns");
            }
            return GoogleAccountType.ACCOUNT_TYPE.equals(cursor.getString(accountType))
                    && cursor.getInt(isReadOnly) != 0
                    && isSystemIdFFC(cursor.getString(systemId))
                    && cursor.getInt(summaryCount) <= 0;
        }
    }
}
 No newline at end of file