resolve merge conflicts of e20a370 to mnc-dev

Test: same test cases as I0310c6e35cb378e1fe22691e5aecdb8ece1a3c9e.
  except ran them on Nexus 5 MOB3OH this time
Bug: 32219099

FPIIM-1289
FPIIM-1283

Change-Id: I6679d55fb0cb7618fd0557375e587375c940eaf0
diff --git a/res/values/strings.xml b/res/values/strings.xml
index ae9f241..0a72f21 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -440,6 +440,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] -->
diff --git a/src/com/android/contacts/common/activity/RequestImportVCardPermissionsActivity.java b/src/com/android/contacts/common/activity/RequestImportVCardPermissionsActivity.java
index f3baf0b..1c313f9 100644
--- a/src/com/android/contacts/common/activity/RequestImportVCardPermissionsActivity.java
+++ b/src/com/android/contacts/common/activity/RequestImportVCardPermissionsActivity.java
@@ -46,9 +46,11 @@
      * 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
diff --git a/src/com/android/contacts/common/activity/RequestPermissionsActivityBase.java b/src/com/android/contacts/common/activity/RequestPermissionsActivityBase.java
index 5f78ec7..a692ab9 100644
--- a/src/com/android/contacts/common/activity/RequestPermissionsActivityBase.java
+++ b/src/com/android/contacts/common/activity/RequestPermissionsActivityBase.java
@@ -39,6 +39,9 @@
  */
 public abstract class RequestPermissionsActivityBase extends Activity {
     public static final String PREVIOUS_ACTIVITY_INTENT = "previous_intent";
+
+    protected static final String EXTRA_IS_CALLER_SELF = "is_caller_self";
+
     private static final int PERMISSIONS_REQUEST_ALL_PERMISSIONS = 1;
 
     /**
@@ -55,10 +58,14 @@
 
     private 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,9 +83,16 @@
      */
     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 (!RequestPermissionsActivity.hasPermissions(activity, requiredPermissions)) {
             final Intent intent = new Intent(activity,  newActivityClass);
             intent.putExtra(PREVIOUS_ACTIVITY_INTENT, activity.getIntent());
+            intent.putExtra(EXTRA_IS_CALLER_SELF, isCallerSelf);
             activity.startActivity(intent);
             activity.finish();
             return true;
@@ -99,7 +113,11 @@
         if (permissions != null && permissions.length > 0
                 && isAllGranted(permissions, grantResults)) {
             mPreviousActivityIntent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
-            startActivity(mPreviousActivityIntent);
+            if (mIsCallerSelf) {
+                startActivityForResult(mPreviousActivityIntent, 0);
+            } else {
+                startActivity(mPreviousActivityIntent);
+            }
             finish();
             overridePendingTransition(0, 0);
         } else {
diff --git a/src/com/android/contacts/common/util/AccountSelectionUtil.java b/src/com/android/contacts/common/util/AccountSelectionUtil.java
index 4302dc4..741979e 100644
--- a/src/com/android/contacts/common/util/AccountSelectionUtil.java
+++ b/src/com/android/contacts/common/util/AccountSelectionUtil.java
@@ -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;
@@ -52,53 +53,53 @@
     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());
@@ -107,11 +108,11 @@
 
         // 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, android.R.layout.simple_list_item_2,
+            new ArrayAdapter<AccountWithDataSet>(activity, android.R.layout.simple_list_item_2,
                     writableAccountList) {
 
             @Override
@@ -142,7 +143,7 @@
 
         if (onClickListener == null) {
             AccountSelectedListener accountSelectedListener =
-                new AccountSelectedListener(context, writableAccountList, resId);
+                new AccountSelectedListener(activity, writableAccountList, resId);
             onClickListener = accountSelectedListener;
         }
         if (onCancelListener == null) {
@@ -152,22 +153,22 @@
                 }
             };
         }
-        return new AlertDialog.Builder(context)
+        return new AlertDialog.Builder(activity)
             .setTitle(R.string.dialog_new_contact_account)
             .setSingleChoiceItems(accountAdapter, 0, onClickListener)
             .setOnCancelListener(onCancelListener)
             .create();
     }
 
-    public static void doImport(Context context, int resId, AccountWithDataSet account,
+   public static void doImport(Activity activity, int resId, AccountWithDataSet account,
             int subscriptionId) {
         switch (resId) {
             case R.string.manage_sim_contacts: {
-                doImportFromSim(context, account, subscriptionId);
+                doImportFromSim(activity, account, subscriptionId);
                 break;
             }
             case R.string.import_from_vcf_file: {
-                doImportFromVcfFile(context, account);
+                doImportFromVcfFile(activity, account);
                 break;
             }
         }
@@ -187,8 +188,8 @@
         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);
@@ -201,6 +202,6 @@
         }
         mVCardShare = false;
         mPath = null;
-        context.startActivity(importIntent);
+        activity.startActivityForResult(importIntent, 0);
     }
 }
diff --git a/src/com/android/contacts/common/vcard/ExportVCardActivity.java b/src/com/android/contacts/common/vcard/ExportVCardActivity.java
index 06448eb..bd29fc8 100644
--- a/src/com/android/contacts/common/vcard/ExportVCardActivity.java
+++ b/src/com/android/contacts/common/vcard/ExportVCardActivity.java
@@ -72,7 +72,8 @@
     protected void onCreate(Bundle bundle) {
         super.onCreate(bundle);
 
-        if (RequestImportVCardPermissionsActivity.startPermissionActivity(this)) {
+        if (RequestImportVCardPermissionsActivity.startPermissionActivity(this,
+                /* isCallerSelf */ false)) {
             return;
         }
 
diff --git a/src/com/android/contacts/common/vcard/ImportVCardActivity.java b/src/com/android/contacts/common/vcard/ImportVCardActivity.java
index 85b1417..82969e9 100644
--- a/src/com/android/contacts/common/vcard/ImportVCardActivity.java
+++ b/src/com/android/contacts/common/vcard/ImportVCardActivity.java
@@ -74,7 +74,7 @@
  * any Dialog in the instance. So this code is careless about the management around managed
  * dialogs stuffs (like how onCreateDialog() is used).
  */
-public class ImportVCardActivity extends Activity {
+public class ImportVCardActivity extends Activity implements ImportVCardDialogFragment.Listener {
     private static final String LOG_TAG = "VCardImport";
 
     private static final int SELECT_ACCOUNT = 0;
@@ -497,7 +497,8 @@
     protected void onCreate(Bundle bundle) {
         super.onCreate(bundle);
 
-        if (RequestImportVCardPermissionsActivity.startPermissionActivity(this)) {
+        if (RequestImportVCardPermissionsActivity.startPermissionActivity(this,
+                isCallerSelf(this))) {
             return;
         }
 
@@ -529,10 +530,44 @@
             }
         }
 
+        if (isCallerSelf(this)) {
+            startImport();
+        } else {
+            ImportVCardDialogFragment.show(this);
+        }
+    }
+
+    private static boolean isCallerSelf(Activity activity) {
+        // {@link Activity#getCallingActivity()} is a safer alternative to
+        // {@link Activity#getCallingPackage()} that works around a
+        // framework bug where getCallingPackage() can sometimes return null even when the
+        // current activity *was* in fact launched via a startActivityForResult() call.
+        //
+        // (The bug happens if the task stack needs to be re-created by the framework after
+        // having been killed due to memory pressure or by the "Don't keep activities"
+        // developer option; see bug 7494866 for the full details.)
+        //
+        // Turns out that {@link Activity#getCallingActivity()} *does* return correct info
+        // even in the case where getCallingPackage() is broken, so the workaround is simply
+        // to get the package name from getCallingActivity().getPackageName() instead.
+        final ComponentName callingActivity = activity.getCallingActivity();
+        if (callingActivity == null) return false;
+        final String packageName = callingActivity.getPackageName();
+        if (packageName == null) return false;
+        return packageName.equals(activity.getApplicationContext().getPackageName());
+    }
+
+    @Override
+    public void onImportVCardConfirmed() {
         startImport();
     }
 
     @Override
+    public void onImportVCardDenied() {
+        finish();
+    }
+
+    @Override
     public void onActivityResult(int requestCode, int resultCode, Intent intent) {
         if (requestCode == SELECT_ACCOUNT) {
             if (resultCode == Activity.RESULT_OK) {
diff --git a/src/com/android/contacts/common/vcard/ImportVCardDialogFragment.java b/src/com/android/contacts/common/vcard/ImportVCardDialogFragment.java
new file mode 100644
index 0000000..ae8ebbc
--- /dev/null
+++ b/src/com/android/contacts/common/vcard/ImportVCardDialogFragment.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2016 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.common.vcard;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.content.DialogInterface;
+import android.os.Bundle;
+
+import com.android.contacts.common.R;
+
+/** Asks for confirmation before importing contacts from a vcard. */
+public class ImportVCardDialogFragment extends DialogFragment {
+
+    /** Callbacks for hosts of the {@link ImportVCardDialogFragment}. */
+    public interface Listener {
+
+        /** Invoked after the user has confirmed that contacts should be imported. */
+        void onImportVCardConfirmed();
+
+        /** Invoked after the user has rejected importing contacts. */
+        void onImportVCardDenied();
+    }
+
+    /** Displays the dialog asking for confirmation before importing contacts. */
+    public static void show(Activity activity) {
+        if (!(activity instanceof Listener)) {
+            throw new IllegalArgumentException(
+                    "Activity must implement " + Listener.class.getName());
+        }
+
+        final ImportVCardDialogFragment dialog = new ImportVCardDialogFragment();
+        dialog.show(activity.getFragmentManager(), "importVCardDialogFragment");
+    }
+
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        return new AlertDialog.Builder(getActivity())
+                .setIconAttribute(android.R.attr.alertDialogIcon)
+                .setMessage(R.string.import_from_vcf_file_confirmation_message)
+                .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int whichButton) {
+                        final Listener listener = (Listener) getActivity();
+                        if (listener != null) {
+                            listener.onImportVCardConfirmed();
+                        }
+                    }
+                })
+                .setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int whichButton) {
+                        final Listener listener = (Listener) getActivity();
+                        if (listener != null) {
+                            listener.onImportVCardDenied();
+                        }
+                    }
+                })
+                .create();
+    }
+}