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

Commit 915ccdd2 authored by Walter Jang's avatar Walter Jang
Browse files

Ask for confirmation before importing from vcard

But only when vcard import is started from outside
the contacts application itself.

Test: Manually confirmed the following behavior

1. When there is 0 or 1 writable contacts providing
   account on the device:
  - Importing contacts from the contacts app itself
    DOES NOT SHOW the new confirmation dialog.  On M+
    devices, if the storage permission has not been
    previously granted or dismissed, the new confirmation
    dialog is also NOT SHOWN after granting the storage
    permission.
  - Sending a vcard to contacts from another application
    DOES SHOW the new confirmation dialog.  On M+
    devices, if the storage permission has not been
    previously granted or dismissed, the new confirmation
    dialog is also SHOWN after granting the storage
    permission.

2. When there are 2 or more writable contacts providing
   accounts on the device:
  - Importing contacts from the contacts app itself
    DOES NOT SHOW the new confirmation dialog, instead the
    existing account picker dialog is displayed.  On M+
    devices, if the storage permission has not been
    previously granted or dismissed, the new confirmation
    dialog is also NOT SHOWN after granting the storage
    permission.
  - Sending a vcard to contacts from another application
    DOES NOT SHOW the new confirmation dialog, instead the
    existing account picker dialog is displayed.  On M+
    devices, if the storage permission has not been
    previously granted or dismissed, sending a vcard to
    contacts from another application also DOES NOT SHOW
    the new confirmation dialog.

Bug: 32219099

Change-Id: I0310c6e35cb378e1fe22691e5aecdb8ece1a3c9e
parent fc8aa1b2
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -1384,6 +1384,9 @@
    <!-- Action string for selecting a .vcf file to import contacts from [CHAR LIMIT=30] -->
    <string name="import_from_vcf_file" product="default">Import from .vcf file</string>

    <!-- Dialog message asking the user for confirmation before starting to import contacts from a .vcf file. [CHAR LIMIT=NONE] -->
    <string name="import_from_vcf_file_confirmation_message" product="default">Import contacts from vCard?</string>

    <!-- Message shown in a Dialog confirming a user's cancel request toward existing vCard import.
         The argument is file name for the vCard import the user wants to cancel.
         [CHAR LIMIT=128] -->
+4 −2
Original line number Diff line number Diff line
@@ -43,9 +43,11 @@ public class RequestImportVCardPermissionsActivity extends RequestPermissionsAct
     * to prompt the user for these permissions. Moreover, finish the current activity.
     *
     * This is designed to be called inside {@link android.app.Activity#onCreate}
     *
     * @param isCallerSelf whether the vcard import was started from the contacts app itself.
     */
    public static boolean startPermissionActivity(Activity activity) {
        return startPermissionActivity(activity, REQUIRED_PERMISSIONS,
    public static boolean startPermissionActivity(Activity activity, boolean isCallerSelf) {
        return startPermissionActivity(activity, REQUIRED_PERMISSIONS, isCallerSelf,
                RequestImportVCardPermissionsActivity.class);
    }
}
 No newline at end of file
+5 −1
Original line number Diff line number Diff line
@@ -76,7 +76,11 @@ public class RequestPermissionsActivity extends RequestPermissionsActivityBase {
        if (permissions != null && permissions.length > 0
                && isAllGranted(permissions, grantResults)) {
            mPreviousActivityIntent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
            if (mIsCallerSelf) {
                startActivityForResult(mPreviousActivityIntent, 0);
            } else {
                startActivity(mPreviousActivityIntent);
            }
            finish();
            overridePendingTransition(0, 0);

+13 −0
Original line number Diff line number Diff line
@@ -45,6 +45,8 @@ public abstract class RequestPermissionsActivityBase extends Activity
    protected static final String EXTRA_STARTED_PERMISSIONS_ACTIVITY =
            "started_permissions_activity";

    protected static final String EXTRA_IS_CALLER_SELF = "is_caller_self";

    private static final int PERMISSIONS_REQUEST_ALL_PERMISSIONS = 1;

    /**
@@ -55,10 +57,14 @@ public abstract class RequestPermissionsActivityBase extends Activity

    protected Intent mPreviousActivityIntent;

    /** If true then start the target activity "for result" after permissions are granted. */
    protected boolean mIsCallerSelf;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mPreviousActivityIntent = (Intent) getIntent().getExtras().get(PREVIOUS_ACTIVITY_INTENT);
        mIsCallerSelf = getIntent().getBooleanExtra(EXTRA_IS_CALLER_SELF, false);

        // Only start a requestPermissions() flow when first starting this activity the first time.
        // The process is likely to be restarted during the permission flow (necessary to enable
@@ -76,10 +82,17 @@ public abstract class RequestPermissionsActivityBase extends Activity
     */
    protected static boolean startPermissionActivity(Activity activity,
            String[] requiredPermissions, Class<?> newActivityClass) {
        return startPermissionActivity(activity, requiredPermissions, /* isCallerSelf */ false,
                newActivityClass);
    }

    protected static boolean startPermissionActivity(Activity activity,
                String[] requiredPermissions, boolean isCallerSelf, Class<?> newActivityClass) {
        if (!hasPermissions(activity, requiredPermissions)) {
            final Intent intent = new Intent(activity,  newActivityClass);
            activity.getIntent().putExtra(EXTRA_STARTED_PERMISSIONS_ACTIVITY, true);
            intent.putExtra(PREVIOUS_ACTIVITY_INTENT, activity.getIntent());
            intent.putExtra(EXTRA_IS_CALLER_SELF, isCallerSelf);
            activity.startActivity(intent);
            activity.finish();
            return true;
+24 −23
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.contacts.common.util;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
@@ -53,53 +54,53 @@ public class AccountSelectionUtil {
    public static class AccountSelectedListener
            implements DialogInterface.OnClickListener {

        final private Context mContext;
        final private Activity mActivity;
        final private int mResId;
        final private int mSubscriptionId;

        final protected List<AccountWithDataSet> mAccountList;

        public AccountSelectedListener(Context context, List<AccountWithDataSet> accountList,
        public AccountSelectedListener(Activity activity, List<AccountWithDataSet> accountList,
                int resId, int subscriptionId) {
            if (accountList == null || accountList.size() == 0) {
                Log.e(LOG_TAG, "The size of Account list is 0.");
            }
            mContext = context;
            mActivity = activity;
            mAccountList = accountList;
            mResId = resId;
            mSubscriptionId = subscriptionId;
        }

        public AccountSelectedListener(Context context, List<AccountWithDataSet> accountList,
        public AccountSelectedListener(Activity activity, List<AccountWithDataSet> accountList,
                int resId) {
            // Subscription id is only needed for importing from SIM card. We can safely ignore
            // its value for SD card importing.
            this(context, accountList, resId, /* subscriptionId = */ -1);
            this(activity, accountList, resId, /* subscriptionId = */ -1);
        }

        public void onClick(DialogInterface dialog, int which) {
            dialog.dismiss();
            doImport(mContext, mResId, mAccountList.get(which), mSubscriptionId);
            doImport(mActivity, mResId, mAccountList.get(which), mSubscriptionId);
        }
    }

    public static Dialog getSelectAccountDialog(Context context, int resId) {
        return getSelectAccountDialog(context, resId, null, null);
    public static Dialog getSelectAccountDialog(Activity activity, int resId) {
        return getSelectAccountDialog(activity, resId, null, null);
    }

    public static Dialog getSelectAccountDialog(Context context, int resId,
    public static Dialog getSelectAccountDialog(Activity activity, int resId,
            DialogInterface.OnClickListener onClickListener) {
        return getSelectAccountDialog(context, resId, onClickListener, null);
        return getSelectAccountDialog(activity, resId, onClickListener, null);
    }

    /**
     * When OnClickListener or OnCancelListener is null, uses a default listener.
     * The default OnCancelListener just closes itself with {@link Dialog#dismiss()}.
     */
    public static Dialog getSelectAccountDialog(Context context, int resId,
    public static Dialog getSelectAccountDialog(Activity activity, int resId,
            DialogInterface.OnClickListener onClickListener,
            DialogInterface.OnCancelListener onCancelListener) {
        final AccountTypeManager accountTypes = AccountTypeManager.getInstance(context);
        final AccountTypeManager accountTypes = AccountTypeManager.getInstance(activity);
        final List<AccountWithDataSet> writableAccountList = accountTypes.getAccounts(true);

        Log.i(LOG_TAG, "The number of available accounts: " + writableAccountList.size());
@@ -108,12 +109,12 @@ public class AccountSelectionUtil {

        // Wrap our context to inflate list items using correct theme
        final Context dialogContext = new ContextThemeWrapper(
                context, android.R.style.Theme_Light);
                activity, android.R.style.Theme_Light);
        final LayoutInflater dialogInflater = (LayoutInflater)dialogContext
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        final ArrayAdapter<AccountWithDataSet> accountAdapter =
            new ArrayAdapter<AccountWithDataSet>(
                    context, R.layout.account_selector_list_item_condensed, writableAccountList) {
                    activity, R.layout.account_selector_list_item_condensed, writableAccountList) {
            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                if (convertView == null) {
@@ -141,7 +142,7 @@ public class AccountSelectionUtil {

        if (onClickListener == null) {
            AccountSelectedListener accountSelectedListener =
                new AccountSelectedListener(context, writableAccountList, resId);
                new AccountSelectedListener(activity, writableAccountList, resId);
            onClickListener = accountSelectedListener;
        }
        if (onCancelListener == null) {
@@ -151,8 +152,8 @@ public class AccountSelectionUtil {
                }
            };
        }
        final AlertDialog.Builder builder = new AlertDialog.Builder(context);
        final TextView title = (TextView) View.inflate(context, R.layout.dialog_title, null);
        final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
        final TextView title = (TextView) View.inflate(activity, R.layout.dialog_title, null);
        title.setText(R.string.dialog_new_contact_account);
        builder.setCustomTitle(title);
        builder.setSingleChoiceItems(accountAdapter, 0, onClickListener);
@@ -161,12 +162,12 @@ public class AccountSelectionUtil {
        return result;
    }

    public static void doImport(Context context, int resId, AccountWithDataSet account,
    public static void doImport(Activity activity, int resId, AccountWithDataSet account,
            int subscriptionId) {
        if (resId == R.string.import_from_sim) {
            doImportFromSim(context, account, subscriptionId);
            doImportFromSim(activity, account, subscriptionId);
        } else if (resId == R.string.import_from_vcf_file) {
            doImportFromVcfFile(context, account);
            doImportFromVcfFile(activity, account);
        }
    }

@@ -184,8 +185,8 @@ public class AccountSelectionUtil {
        context.startActivity(importIntent);
    }

    public static void doImportFromVcfFile(Context context, AccountWithDataSet account) {
        Intent importIntent = new Intent(context, ImportVCardActivity.class);
    public static void doImportFromVcfFile(Activity activity, AccountWithDataSet account) {
        Intent importIntent = new Intent(activity, ImportVCardActivity.class);
        if (account != null) {
            importIntent.putExtra("account_name", account.name);
            importIntent.putExtra("account_type", account.type);
@@ -198,6 +199,6 @@ public class AccountSelectionUtil {
        }
        mVCardShare = false;
        mPath = null;
        context.startActivity(importIntent);
        activity.startActivityForResult(importIntent, 0);
    }
}
Loading