Merge "Fixing tests that did not get updated earlier" into froyo
diff --git a/src/com/android/contacts/ImportVCardActivity.java b/src/com/android/contacts/ImportVCardActivity.java
index a8b3f1e..4dcf5d5 100644
--- a/src/com/android/contacts/ImportVCardActivity.java
+++ b/src/com/android/contacts/ImportVCardActivity.java
@@ -31,6 +31,7 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Environment;
+import android.os.FileUtils;
 import android.os.Handler;
 import android.os.PowerManager;
 import android.pim.vcard.VCardConfig;
@@ -53,9 +54,12 @@
 import android.text.style.RelativeSizeSpan;
 import android.util.Log;
 
+import java.io.BufferedOutputStream;
 import java.io.File;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.OutputStream;
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
@@ -153,6 +157,7 @@
         private boolean mCanceled;
         private PowerManager.WakeLock mWakeLock;
         private Uri mUri;
+        private File mTempFile;
 
         private List<VCardFile> mSelectedVCardFileList;
         private List<String> mErrorFileNameList;
@@ -190,11 +195,18 @@
             boolean shouldCallFinish = true;
             mWakeLock.acquire();
             Uri createdUri = null;
+            mTempFile = null;
             // Some malicious vCard data may make this thread broken
             // (e.g. OutOfMemoryError).
             // Even in such cases, some should be done.
             try {
                 if (mUri != null) {  // Read one vCard expressed by mUri
+                    final Uri uri = getReopenableUri(mUri);
+                    if (uri == null) {
+                        shouldCallFinish = false;
+                        return;
+                    }
+
                     mProgressDialogForReadVCard.setProgressNumberFormat("");
                     mProgressDialogForReadVCard.setProgress(0);
 
@@ -208,16 +220,15 @@
                     VCardSourceDetector detector = new VCardSourceDetector();
                     VCardInterpreterCollection builderCollection = new VCardInterpreterCollection(
                             Arrays.asList(counter, detector));
-
                     boolean result;
                     try {
-                        result = readOneVCardFile(mUri,
+                        result = readOneVCardFile(uri,
                                 VCardConfig.DEFAULT_CHARSET, builderCollection, null, true, null);
                     } catch (VCardNestedException e) {
                         try {
                             // Assume that VCardSourceDetector was able to detect the source.
                             // Try again with the detector.
-                            result = readOneVCardFile(mUri,
+                            result = readOneVCardFile(uri,
                                     VCardConfig.DEFAULT_CHARSET, counter, detector, false, null);
                         } catch (VCardNestedException e2) {
                             result = false;
@@ -239,7 +250,7 @@
                     mProgressDialogForReadVCard.setIndeterminate(false);
                     mProgressDialogForReadVCard.setMax(counter.getCount());
                     String charset = detector.getEstimatedCharset();
-                    createdUri = doActuallyReadOneVCard(mUri, null, charset, true, detector,
+                    createdUri = doActuallyReadOneVCard(uri, null, charset, true, detector,
                             mErrorFileNameList);
                 } else {  // Read multiple files.
                     mProgressDialogForReadVCard.setProgressNumberFormat(
@@ -251,7 +262,13 @@
                         if (mCanceled) {
                             return;
                         }
-                        final Uri uri = Uri.parse("file://" + vcardFile.getCanonicalPath());
+                        // TODO: detect scheme!
+                        final Uri uri = getReopenableUri(
+                                Uri.parse("file://" + vcardFile.getCanonicalPath()));
+                        if (uri == null) {
+                            shouldCallFinish = false;
+                            return;
+                        }
 
                         VCardSourceDetector detector = new VCardSourceDetector();
                         try {
@@ -271,6 +288,12 @@
             } finally {
                 mWakeLock.release();
                 mProgressDialogForReadVCard.dismiss();
+                if (mTempFile != null) {
+                    if (!mTempFile.delete()) {
+                        Log.w(LOG_TAG, "Failed to delete a cache file.");
+                    }
+                    mTempFile = null;
+                }
                 // finish() is called via mCancelListener, which is used in DialogDisplayer.
                 if (shouldCallFinish && !isFinishing()) {
                     if (mErrorFileNameList == null || mErrorFileNameList.isEmpty()) {
@@ -310,6 +333,49 @@
             }
         }
 
+        private Uri getReopenableUri(final Uri uri) {
+            if ("file".equals(uri.getScheme())) {
+                return uri;
+            } else {
+                // We may not be able to scan a given uri more than once when it does not
+                // point to a local file, while it is necessary to scan it more than once
+                // because of vCard limitation. We rely on a local temporary file instead.
+                //
+                // e.g. Email app's AttachmentProvider is able to give us a content Uri
+                // with an attachment file, but we cannot "sometimes" (not always) scan
+                // the Uri more than once because of permission revocation.
+                InputStream is = null;
+                OutputStream os = null;
+                Uri reopenableUri = null;
+                try {
+                    is = mResolver.openInputStream(uri);
+                    File dir = getDir("tmp", MODE_PRIVATE);
+                    mTempFile = dir.createTempFile("vcf", null, dir);
+                    FileUtils.copyToFile(is, mTempFile);
+                    reopenableUri = Uri.parse("file://" + mTempFile.getCanonicalPath());
+                } catch (IOException e) {
+                    mHandler.post(new DialogDisplayer(
+                            getString(R.string.fail_reason_io_error) +
+                            ": " + e.getLocalizedMessage()));
+                    return null;
+                } finally {
+                    if (is != null) {
+                        try {
+                            is.close();
+                        } catch (IOException e) {
+                        }
+                    }
+                    if (os != null) {
+                        try {
+                            os.close();
+                        } catch (IOException e) {
+                        }
+                    }
+                }
+                return reopenableUri;
+            }
+        }
+
         private Uri doActuallyReadOneVCard(Uri uri, Account account,
                 String charset, boolean showEntryParseProgress,
                 VCardSourceDetector detector, List<String> errorFileNameList) {
diff --git a/src/com/android/contacts/ViewContactActivity.java b/src/com/android/contacts/ViewContactActivity.java
index 2b2a8f7..ead6a4a 100644
--- a/src/com/android/contacts/ViewContactActivity.java
+++ b/src/com/android/contacts/ViewContactActivity.java
@@ -402,7 +402,7 @@
 
         // Contains an Id.
         final long uriContactId = Long.parseLong(segments.get(3));
-        final String uriLookupKey = segments.get(2);
+        final String uriLookupKey = Uri.encode(segments.get(2));
         final Uri dataUri = Uri.withAppendedPath(
                 ContentUris.withAppendedId(Contacts.CONTENT_URI, uriContactId),
                 Contacts.Data.CONTENT_DIRECTORY);