Add share voicemail functionality.

+Send intent to other applications with temporary file permission
granted
+Add voicemails folder to FileProvider paths
+When creating file in VoicemailArchiveProvider, append extension to
file name
+Check voicemail content exists before archiving it
+Refactor voicemail code
+Add tests for checking file extension
+Add tests for archiving and sharing vociemails
+Archive tab should not archive on share button press

BUG=22798485

Change-Id: Id8068aba92f7f1ca58532dca6c405cb2908841a3
diff --git a/res/xml/file_paths.xml b/res/xml/file_paths.xml
index 45caed2..365a603 100644
--- a/res/xml/file_paths.xml
+++ b/res/xml/file_paths.xml
@@ -16,5 +16,7 @@
 
 <paths xmlns:android="http://schemas.android.com/apk/res/android">
     <!-- Offer access to files under Context.getCacheDir() -->
-    <cache-path name="my_cache" />
+     <cache-path name="my_cache" />
+     <!-- Offer access to voicemail folder under Context.getFilesDir() -->
+     <files-path name="voicemails" path="voicemails/" />
 </paths>
diff --git a/src/com/android/dialer/database/VoicemailArchiveProvider.java b/src/com/android/dialer/database/VoicemailArchiveProvider.java
index 79b7a76..b3306bc 100644
--- a/src/com/android/dialer/database/VoicemailArchiveProvider.java
+++ b/src/com/android/dialer/database/VoicemailArchiveProvider.java
@@ -28,6 +28,7 @@
 import android.os.ParcelFileDescriptor;
 import android.support.annotation.Nullable;
 import android.text.TextUtils;
+import android.webkit.MimeTypeMap;
 
 import com.android.dialerbind.DatabaseHelperManager;
 import com.google.common.annotations.VisibleForTesting;
@@ -119,7 +120,11 @@
 
         // Create new file only if path is not provided to one
         if (!values.containsKey(VoicemailArchiveContract.VoicemailArchive._DATA)) {
-            File voicemailFile = new File(directory, Long.toString(id));
+            String fileExtension = MimeTypeMap.getSingleton().getExtensionFromMimeType(
+                    values.getAsString(VoicemailArchiveContract.VoicemailArchive.MIME_TYPE));
+            File voicemailFile = new File(directory,
+                    TextUtils.isEmpty(fileExtension) ? Long.toString(id) :
+                            id + "." + fileExtension);
             values.put(VoicemailArchiveContract.VoicemailArchive._DATA, voicemailFile.getPath());
         }
         update(newUri, values, null, null);
diff --git a/src/com/android/dialer/voicemail/VoicemailArchivePlaybackPresenter.java b/src/com/android/dialer/voicemail/VoicemailArchivePlaybackPresenter.java
index 050b8ac..5f73d16 100644
--- a/src/com/android/dialer/voicemail/VoicemailArchivePlaybackPresenter.java
+++ b/src/com/android/dialer/voicemail/VoicemailArchivePlaybackPresenter.java
@@ -62,7 +62,6 @@
                     }
                 } catch (FileNotFoundException e) {
                     Log.d(TAG, "Voicemail file not found for " + mVoicemailUri);
-                    handleError(e);
                 }
                 return false;
             }
@@ -75,11 +74,17 @@
     }
 
     @Override
-    protected boolean requestContent(int code) {
-        if (mContext == null || mVoicemailUri == null) {
-            return false;
+    protected void startArchiveVoicemailTask(final Uri voicemailUri, final boolean archivedByUser) {
+        // If a user wants to share an archived voicemail, no need for archiving, just go straight
+        // to share intent.
+        if (!archivedByUser) {
+            sendShareIntent(voicemailUri);
         }
-        prepareContent();
-        return true;
+    }
+
+    @Override
+    protected boolean requestContent(int code) {
+        handleError(new FileNotFoundException("Voicemail archive file does not exist"));
+        return false;       // No way for archive tab to request content
     }
 }
diff --git a/src/com/android/dialer/voicemail/VoicemailPlaybackLayout.java b/src/com/android/dialer/voicemail/VoicemailPlaybackLayout.java
index 8c869d1..e5efbec 100644
--- a/src/com/android/dialer/voicemail/VoicemailPlaybackLayout.java
+++ b/src/com/android/dialer/voicemail/VoicemailPlaybackLayout.java
@@ -258,6 +258,17 @@
         }
     };
 
+    private final View.OnClickListener mShareButtonListener = new View.OnClickListener() {
+        @Override
+        public void onClick(View v) {
+            if (mPresenter == null || isArchiving(mVoicemailUri)) {
+                return;
+            }
+            disableUiElements();
+            mPresenter.archiveContent(mVoicemailUri, false);
+        }
+    };
+
     private Context mContext;
     private VoicemailPlaybackPresenter mPresenter;
     private Uri mVoicemailUri;
@@ -339,6 +350,7 @@
         mPlaybackSpeakerphone.setOnClickListener(mSpeakerphoneListener);
         mDeleteButton.setOnClickListener(mDeleteButtonListener);
         mArchiveButton.setOnClickListener(mArchiveButtonListener);
+        mShareButton.setOnClickListener(mShareButtonListener);
 
         mPositionText.setText(formatAsMinutesAndSeconds(0));
         mTotalDurationText.setText(formatAsMinutesAndSeconds(0));
diff --git a/src/com/android/dialer/voicemail/VoicemailPlaybackPresenter.java b/src/com/android/dialer/voicemail/VoicemailPlaybackPresenter.java
index 3151a5e..5924fb4 100644
--- a/src/com/android/dialer/voicemail/VoicemailPlaybackPresenter.java
+++ b/src/com/android/dialer/voicemail/VoicemailPlaybackPresenter.java
@@ -19,11 +19,8 @@
 import com.google.common.annotations.VisibleForTesting;
 
 import android.app.Activity;
-import android.content.ContentUris;
-import android.content.ContentValues;
 import android.content.Context;
 import android.content.ContentResolver;
-import android.content.Context;
 import android.content.Intent;
 import android.database.ContentObserver;
 import android.database.Cursor;
@@ -33,24 +30,19 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.PowerManager;
-import android.provider.CallLog;
 import android.provider.VoicemailContract;
-import android.support.annotation.Nullable;
+import android.support.v4.content.FileProvider;
 import android.util.Log;
 import android.view.WindowManager.LayoutParams;
 
+import com.android.dialer.R;
 import com.android.dialer.calllog.CallLogAsyncTaskUtil;
-import com.android.dialer.calllog.CallLogQuery;
-import com.android.dialer.database.VoicemailArchiveContract;
 import com.android.dialer.util.AsyncTaskExecutor;
 import com.android.dialer.util.AsyncTaskExecutors;
 import com.android.common.io.MoreCloseables;
-import com.android.dialer.util.TelecomUtil;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.io.ByteStreams;
+
+import java.io.File;
 import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.Executors;
@@ -140,6 +132,7 @@
             VoicemailPlaybackPresenter.class.getName() + ".IS_SPEAKER_PHONE_ON";
     public static final int PLAYBACK_REQUEST = 0;
     public static final int ARCHIVE_REQUEST = 1;
+    public static final int SHARE_REQUEST = 2;
 
     /**
      * The most recently cached duration. We cache this since we don't want to keep requesting it
@@ -181,6 +174,7 @@
     private VoicemailAudioManager mVoicemailAudioManager;
 
     private OnVoicemailDeletedListener mOnVoicemailDeletedListener;
+    private final VoicemailAsyncTaskUtil mVoicemailAsyncTaskUtil;
 
     /**
      * Obtain singleton instance of this class. Use a single instance to provide a consistent
@@ -208,6 +202,7 @@
         Context context = activity.getApplicationContext();
         mAsyncTaskExecutor = AsyncTaskExecutors.createAsyncTaskExecutor();
         mVoicemailAudioManager = new VoicemailAudioManager(context, this);
+        mVoicemailAsyncTaskUtil = new VoicemailAsyncTaskUtil(context.getContentResolver());
         PowerManager powerManager =
                 (PowerManager) context.getSystemService(Context.POWER_SERVICE);
         if (powerManager.isWakeLockLevelSupported(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK)) {
@@ -493,7 +488,6 @@
         private final Handler mFetchResultHandler;
         private final Uri mVoicemailUri;
         private final int mRequestCode;
-        private Uri mArchivedVoicemailUri;
 
         public FetchResultHandler(Handler handler, Uri uri, int code) {
             super(handler);
@@ -515,11 +509,7 @@
             if (mIsWaitingForResult.getAndSet(false) && mContext != null) {
                 mContext.getContentResolver().unregisterContentObserver(this);
                 if (mView != null) {
-                    if (mRequestCode == ARCHIVE_REQUEST) {
-                        notifyUiOfArchiveResult(mVoicemailUri, false);
-                    } else {
-                        mView.setFetchContentTimeout();
-                    }
+                    mView.setFetchContentTimeout();
                 }
             }
         }
@@ -538,13 +528,7 @@
 
                 @Override
                 public Boolean doInBackground(Void... params) {
-                    boolean hasContent = queryHasContent(mVoicemailUri);
-                    if (hasContent && mRequestCode == ARCHIVE_REQUEST) {
-                        mArchivedVoicemailUri =
-                                performArchiveVoicemailOnBackgroundThread(mVoicemailUri, true);
-                        return mArchivedVoicemailUri != null;
-                    }
-                    return hasContent;
+                    return queryHasContent(mVoicemailUri);
                 }
 
                 @Override
@@ -552,11 +536,11 @@
                     if (hasContent && mContext != null && mIsWaitingForResult.getAndSet(false)) {
                         mContext.getContentResolver().unregisterContentObserver(
                                 FetchResultHandler.this);
-                        switch (mRequestCode) {
-                            case ARCHIVE_REQUEST:
-                                notifyUiOfArchiveResult(mVoicemailUri, true);
-                            default:
-                                prepareContent();
+                        prepareContent();
+                        if (mRequestCode == ARCHIVE_REQUEST) {
+                            startArchiveVoicemailTask(mVoicemailUri, true /* archivedByUser */);
+                        } else if (mRequestCode == SHARE_REQUEST) {
+                            startArchiveVoicemailTask(mVoicemailUri, false /* archivedByUser */);
                         }
                     }
                 }
@@ -922,148 +906,89 @@
      * If voicemail has already been downloaded, go straight to archiving. Otherwise, request
      * the voicemail content first.
      */
-    public void archiveContent(Uri voicemailUri, boolean archivedByUser) {
-        if (!mIsPrepared) {
-            requestContent(ARCHIVE_REQUEST);
-        } else {
-            startArchiveVoicemailTask(voicemailUri, archivedByUser);
-        }
-    }
-
-    /**
-     * Asynchronous task used to archive a voicemail given its uri.
-     */
-    private void startArchiveVoicemailTask(final Uri voicemailUri, final boolean archivedByUser) {
-        mAsyncTaskExecutor.submit(Tasks.ARCHIVE_VOICEMAIL, new AsyncTask<Void, Void, Uri>() {
+    public void archiveContent(final Uri voicemailUri, final boolean archivedByUser) {
+        checkForContent(new OnContentCheckedListener() {
             @Override
-            public Uri doInBackground(Void... params) {
-                return performArchiveVoicemailOnBackgroundThread(voicemailUri, archivedByUser);
-            }
-
-            @Override
-            public void onPostExecute(Uri archivedVoicemailUri) {
-                notifyUiOfArchiveResult(voicemailUri, archivedVoicemailUri != null);
+            public void onContentChecked(boolean hasContent) {
+                if (!hasContent) {
+                    requestContent(archivedByUser ? ARCHIVE_REQUEST : SHARE_REQUEST);
+                } else {
+                    startArchiveVoicemailTask(voicemailUri, archivedByUser);
+                }
             }
         });
     }
 
     /**
-     * Copy the voicemail information to the local dialer database, and copy
-     * the voicemail content to a local file in the dialer application's
-     * internal storage (voicemails directory).
-     *
-     * @param voicemailUri the uri of the voicemail to archive
-     * @return If archive was successful, archived voicemail URI, otherwise null.
+     * Asynchronous task used to archive a voicemail given its uri.
      */
-    private Uri performArchiveVoicemailOnBackgroundThread(Uri voicemailUri,
-                                                          boolean archivedByUser) {
-        Cursor callLogInfo = mContext.getContentResolver().query(
-                ContentUris.withAppendedId(CallLog.Calls.CONTENT_URI_WITH_VOICEMAIL,
-                        ContentUris.parseId(mVoicemailUri)),
-                CallLogQuery._PROJECTION, null, null, null);
-        Cursor contentInfo = mContext.getContentResolver().query(
-                voicemailUri, null, null, null, null);
+    protected void startArchiveVoicemailTask(final Uri voicemailUri, final boolean archivedByUser) {
+        mVoicemailAsyncTaskUtil.archiveVoicemailContent(
+                new VoicemailAsyncTaskUtil.OnArchiveVoicemailListener() {
+                    @Override
+                    public void onArchiveVoicemail(final Uri archivedVoicemailUri) {
+                        if (archivedVoicemailUri == null) {
+                            notifyUiOfArchiveResult(voicemailUri, false);
+                            return;
+                        }
 
-        if (callLogInfo == null || contentInfo == null) {
-            return null;
-        }
+                        if (archivedByUser) {
+                            setArchivedVoicemailStatusAndUpdateUI(voicemailUri,
+                                    archivedVoicemailUri, true);
+                        } else {
+                            sendShareIntent(archivedVoicemailUri);
+                        }
+                    }
+                }, voicemailUri);
+    }
 
-        callLogInfo.moveToFirst();
-        contentInfo.moveToFirst();
+    /**
+     * Sends the intent for sharing the voicemail file.
+     */
+    protected void sendShareIntent(final Uri voicemailUri) {
+        mVoicemailAsyncTaskUtil.getVoicemailFilePath(
+                new VoicemailAsyncTaskUtil.OnGetArchivedVoicemailFilePathListener() {
+                    @Override
+                    public void onGetArchivedVoicemailFilePath(String filePath) {
+                        mView.enableUiElements();
+                        if (filePath == null) {
+                            mView.setFetchContentTimeout();
+                            return;
+                        }
+                        Uri voicemailFileUri = FileProvider.getUriForFile(
+                                mContext,
+                                mContext.getString(R.string.contacts_file_provider_authority),
+                                new File(filePath));
+                        mContext.startActivity(Intent.createChooser(
+                                getShareIntent(voicemailFileUri),
+                                mContext.getResources().getText(
+                                        R.string.call_log_share_voicemail)));
+                    }
+                }, voicemailUri);
+    }
 
-        // Create values to insert into database
-        ContentValues values = new ContentValues();
-        values.put(VoicemailArchiveContract.VoicemailArchive.NUMBER,
-                contentInfo.getString(contentInfo.getColumnIndex(
-                        VoicemailContract.Voicemails.NUMBER)));
+    /** Sets archived_by_user field to the given boolean and updates the URI. */
+    private void setArchivedVoicemailStatusAndUpdateUI(
+            final Uri voicemailUri,
+            final Uri archivedVoicemailUri,
+            boolean status) {
+        mVoicemailAsyncTaskUtil.setVoicemailArchiveStatus(
+                new VoicemailAsyncTaskUtil.OnSetVoicemailArchiveStatusListener() {
+                    @Override
+                    public void onSetVoicemailArchiveStatus(boolean success) {
+                        notifyUiOfArchiveResult(voicemailUri, success);
+                    }
+                }, archivedVoicemailUri, status);
+    }
 
-        values.put(VoicemailArchiveContract.VoicemailArchive.DATE,
-                contentInfo.getLong(contentInfo.getColumnIndex(
-                        VoicemailContract.Voicemails.DATE)));
-
-        values.put(VoicemailArchiveContract.VoicemailArchive.DURATION,
-                contentInfo.getLong(contentInfo.getColumnIndex(
-                        VoicemailContract.Voicemails.DURATION)));
-
-        values.put(VoicemailArchiveContract.VoicemailArchive.MIME_TYPE,
-                contentInfo.getString(contentInfo.getColumnIndex(
-                        VoicemailContract.Voicemails.MIME_TYPE)));
-
-        values.put(VoicemailArchiveContract.VoicemailArchive.COUNTRY_ISO,
-                callLogInfo.getString(CallLogQuery.COUNTRY_ISO));
-
-        values.put(VoicemailArchiveContract.VoicemailArchive.GEOCODED_LOCATION,
-                callLogInfo.getString(CallLogQuery.GEOCODED_LOCATION));
-
-        values.put(VoicemailArchiveContract.VoicemailArchive.CACHED_NAME,
-                callLogInfo.getString(CallLogQuery.CACHED_NAME));
-
-        values.put(VoicemailArchiveContract.VoicemailArchive.CACHED_NUMBER_TYPE,
-                callLogInfo.getInt(CallLogQuery.CACHED_NUMBER_TYPE));
-
-        values.put(VoicemailArchiveContract.VoicemailArchive.CACHED_NUMBER_LABEL,
-                callLogInfo.getString(CallLogQuery.CACHED_NUMBER_LABEL));
-
-        values.put(VoicemailArchiveContract.VoicemailArchive.CACHED_LOOKUP_URI,
-                callLogInfo.getString(CallLogQuery.CACHED_LOOKUP_URI));
-
-        values.put(VoicemailArchiveContract.VoicemailArchive.CACHED_MATCHED_NUMBER,
-                callLogInfo.getString(CallLogQuery.CACHED_MATCHED_NUMBER));
-
-        values.put(VoicemailArchiveContract.VoicemailArchive.CACHED_NORMALIZED_NUMBER,
-                callLogInfo.getString(CallLogQuery.CACHED_NORMALIZED_NUMBER));
-
-        values.put(VoicemailArchiveContract.VoicemailArchive.CACHED_FORMATTED_NUMBER,
-                callLogInfo.getString(CallLogQuery.CACHED_FORMATTED_NUMBER));
-
-        values.put(VoicemailArchiveContract.VoicemailArchive.ARCHIVED, archivedByUser);
-
-        values.put(VoicemailArchiveContract.VoicemailArchive.NUMBER_PRESENTATION,
-                callLogInfo.getInt(CallLogQuery.NUMBER_PRESENTATION));
-
-        values.put(VoicemailArchiveContract.VoicemailArchive.ACCOUNT_COMPONENT_NAME,
-                callLogInfo.getString(CallLogQuery.ACCOUNT_COMPONENT_NAME));
-
-        values.put(VoicemailArchiveContract.VoicemailArchive.ACCOUNT_ID,
-                callLogInfo.getString(CallLogQuery.ACCOUNT_ID));
-
-        values.put(VoicemailArchiveContract.VoicemailArchive.FEATURES,
-                callLogInfo.getInt(CallLogQuery.FEATURES));
-
-        values.put(VoicemailArchiveContract.VoicemailArchive.SERVER_ID,
-                contentInfo.getInt(contentInfo.getColumnIndex(
-                        VoicemailContract.Voicemails._ID)));
-
-        values.put(VoicemailArchiveContract.VoicemailArchive.TRANSCRIPTION,
-                contentInfo.getString(contentInfo.getColumnIndex(
-                        VoicemailContract.Voicemails.TRANSCRIPTION)));
-
-        values.put(VoicemailArchiveContract.VoicemailArchive.CACHED_PHOTO_URI,
-                callLogInfo.getLong(CallLogQuery.CACHED_PHOTO_URI));
-
-        callLogInfo.close();
-        contentInfo.close();
-
-        // Insert info into dialer database
-        Uri archivedVoicemailUri = mContext.getContentResolver().insert(
-                        VoicemailArchiveContract.VoicemailArchive.CONTENT_URI, values);
-        try {
-            // Copy voicemail content to a local file
-            InputStream inputStream = mContext.getContentResolver()
-                    .openInputStream(voicemailUri);
-            OutputStream outputStream = mContext.getContentResolver()
-                    .openOutputStream(archivedVoicemailUri);
-
-            ByteStreams.copy(inputStream, outputStream);
-            inputStream.close();
-            outputStream.close();
-        } catch (IOException e) {
-            // Roll back insert if new file creation failed
-            mContext.getContentResolver().delete(archivedVoicemailUri, null, null);
-            Log.w(TAG, "Failed to copy voicemail content to temporary file");
-            return null;
-        }
-        return archivedVoicemailUri;
+    private Intent getShareIntent(Uri voicemailFileUri) {
+        Intent shareIntent = new Intent();
+        shareIntent.setAction(Intent.ACTION_SEND);
+        shareIntent.putExtra(Intent.EXTRA_STREAM, voicemailFileUri);
+        shareIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+        shareIntent.setType(mContext.getContentResolver()
+                .getType(voicemailFileUri));
+        return shareIntent;
     }
 
     @VisibleForTesting
diff --git a/tests/src/com/android/dialer/database/VoicemailArchiveProviderTest.java b/tests/src/com/android/dialer/database/VoicemailArchiveProviderTest.java
index cec7e05..abc2dc5 100644
--- a/tests/src/com/android/dialer/database/VoicemailArchiveProviderTest.java
+++ b/tests/src/com/android/dialer/database/VoicemailArchiveProviderTest.java
@@ -79,6 +79,33 @@
         assertTrue(doesFileExist());
     }
 
+    public void testQuery_createFileMimeTypeIsAMR() throws Exception {
+        insertVoicemailWithMimeType("audio/amr");
+        assertTrue(doesRowExist());
+        assertFalse(doesFileExist());
+        createFile();
+        assertTrue(doesFileExist());
+        assertEquals("amr", getFileExtension(getFilePath()));
+    }
+
+    public void testQuery_createFileMimeTypeIsMP3() throws Exception {
+        insertVoicemailWithMimeType("audio/mpeg");
+        assertTrue(doesRowExist());
+        assertFalse(doesFileExist());
+        createFile();
+        assertTrue(doesFileExist());
+        assertEquals("mp3", getFileExtension(getFilePath()));
+    }
+
+    public void testQuery_createFileMimeTypeNotExists() throws Exception {
+        insertVoicemailWithMimeType(TEST_STRING);
+        assertTrue(doesRowExist());
+        assertFalse(doesFileExist());
+        createFile();
+        assertTrue(doesFileExist());
+        assertEquals("", getFileExtension(getFilePath()));
+    }
+
     public void testQuery() {
         insertVoicemail();
         updateCursor();
@@ -179,6 +206,13 @@
         return voicemailFile.exists();
     }
 
+    private static String getFileExtension(String filePath) {
+        File file = new File(filePath);
+        String fileName = file.getName();
+        int index = fileName.lastIndexOf(".");
+        return index > 0 ? fileName.substring(index + 1) : "";
+    }
+
     private void assertCursorCount(int count) {
         assertEquals(count, mCursor.getCount());
     }
@@ -196,6 +230,12 @@
         mVoicemailUri = mResolver.insert(VoicemailArchive.CONTENT_URI, getTestValues());
     }
 
+    private void insertVoicemailWithMimeType(String mimeType) {
+        ContentValues values = getTestValues();
+        values.put(VoicemailArchive.MIME_TYPE, mimeType);
+        mVoicemailUri = mResolver.insert(VoicemailArchive.CONTENT_URI, values);
+    }
+
     private void updateCursor() {
         mCursor = mResolver.query(mVoicemailUri, null, null, null, null);
         assertEquals(true, mCursor.getCount() > 0);
@@ -226,7 +266,7 @@
         return mCursor.getString(mCursor.getColumnIndex(VoicemailArchive._DATA));
     }
 
-    private ContentValues getTestValues() {
+    private static ContentValues getTestValues() {
         ContentValues values = new ContentValues();
         values.put(VoicemailArchive.NUMBER, TEST_NUMBER);
         values.put(VoicemailArchive.MIME_TYPE, TEST_MIME_TYPE);
diff --git a/tests/src/com/android/dialer/voicemail/VoicemailActivityInstrumentationTestCase2.java b/tests/src/com/android/dialer/voicemail/VoicemailActivityInstrumentationTestCase2.java
index a992e8b..cabaf67 100644
--- a/tests/src/com/android/dialer/voicemail/VoicemailActivityInstrumentationTestCase2.java
+++ b/tests/src/com/android/dialer/voicemail/VoicemailActivityInstrumentationTestCase2.java
@@ -1,3 +1,19 @@
+/*
+ * 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.dialer.voicemail;
 
 import android.app.Activity;
@@ -23,7 +39,6 @@
 
 import static com.android.dialer.voicemail.VoicemailPlaybackPresenter.Tasks.CHECK_FOR_CONTENT;
 
-
 /**
  * Common methods and attributes between {@link VoicemailArchiveTest} and
  * {@link VoicemailPlaybackTest}.
diff --git a/tests/src/com/android/dialer/voicemail/VoicemailArchiveTest.java b/tests/src/com/android/dialer/voicemail/VoicemailArchiveTest.java
index 8cbd344..bbd5edc 100644
--- a/tests/src/com/android/dialer/voicemail/VoicemailArchiveTest.java
+++ b/tests/src/com/android/dialer/voicemail/VoicemailArchiveTest.java
@@ -15,14 +15,12 @@
  */
 
 package com.android.dialer.voicemail;
+
 import android.content.ContentUris;
 import android.content.ContentValues;
-
-import com.android.dialer.R;
-import com.android.dialer.database.VoicemailArchiveContract.VoicemailArchive;
-
 import android.content.res.AssetManager;
-import android.test.suitebuilder.annotation.Suppress;
+
+import com.android.dialer.database.VoicemailArchiveContract.VoicemailArchive;
 
 import java.io.IOException;
 import java.io.InputStream;
diff --git a/tests/src/com/android/dialer/voicemail/VoicemailPlaybackTest.java b/tests/src/com/android/dialer/voicemail/VoicemailPlaybackTest.java
index abd582b..be9905e 100644
--- a/tests/src/com/android/dialer/voicemail/VoicemailPlaybackTest.java
+++ b/tests/src/com/android/dialer/voicemail/VoicemailPlaybackTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 The Android Open Source Project
+ * 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.
@@ -16,10 +16,14 @@
 
 package com.android.dialer.voicemail;
 
+import android.content.ContentUris;
+import android.database.Cursor;
+import android.net.Uri;
 import android.test.suitebuilder.annotation.Suppress;
 
 import com.android.dialer.calllog.CallLogActivity;
-
+import com.android.dialer.database.VoicemailArchiveContract;
+import static com.android.dialer.voicemail.VoicemailAsyncTaskUtil.Tasks.ARCHIVE_VOICEMAIL_CONTENT;
 import static com.android.dialer.voicemail.VoicemailPlaybackPresenter.Tasks.CHECK_FOR_CONTENT;
 
 /**
@@ -38,6 +42,12 @@
         mPresenter = VoicemailPlaybackPresenter.getInstance(getActivity(), null);
     }
 
+    @Override
+    public void tearDown() throws Exception {
+        cleanUpArchivedVoicemailUri();
+        super.tearDown();
+    }
+
     @Suppress
     public void testWhenCheckForContentCompletes() throws Throwable {
         setUriForRealFileVoicemailEntry();
@@ -54,4 +64,82 @@
 
         assertStateTextContains("Loading voicemail");
     }
+
+    public void testArchiveContent() throws Throwable {
+        setUriForRealFileVoicemailEntry();
+        setPlaybackViewForPresenter();
+        mFakeAsyncTaskExecutor.runTask(CHECK_FOR_CONTENT);
+
+        getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mPresenter.archiveContent(mVoicemailUri, true);
+            }
+        });
+        mFakeAsyncTaskExecutor.runTask(CHECK_FOR_CONTENT);
+        mFakeAsyncTaskExecutor.runTask(ARCHIVE_VOICEMAIL_CONTENT);
+        getInstrumentation().waitForIdleSync();
+        assertVoicemailArchived();
+    }
+
+    public void testShareContent() throws Throwable {
+        setUriForRealFileVoicemailEntry();
+        setPlaybackViewForPresenter();
+        mFakeAsyncTaskExecutor.runTask(CHECK_FOR_CONTENT);
+
+        getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mPresenter.archiveContent(mVoicemailUri, false);
+            }
+        });
+        mFakeAsyncTaskExecutor.runTask(CHECK_FOR_CONTENT);
+        mFakeAsyncTaskExecutor.runTask(ARCHIVE_VOICEMAIL_CONTENT);
+        getInstrumentation().waitForIdleSync();
+        assertVoicemailArchived();
+    }
+
+    private void assertVoicemailArchived() {
+        try (Cursor cursor = getArchivedVoicemailCursor()) {
+            assertTrue(hasContent(cursor));
+            assertEquals(ContentUris.parseId(mVoicemailUri), getRowServerId(cursor));
+        } catch (Exception e) {
+            fail("Voicemail was not archived: " + e.toString());
+        }
+    }
+
+    private void cleanUpArchivedVoicemailUri() {
+        try (Cursor cursor = getArchivedVoicemailCursor()) {
+            if (hasContent(cursor)) {
+                getContentResolver().delete(getRowUri(cursor), null, null);
+            }
+        }
+    }
+
+    private Cursor getArchivedVoicemailCursor() {
+        return getContentResolver().query(
+                VoicemailArchiveContract.VoicemailArchive.CONTENT_URI,
+                new String[] {
+                        VoicemailArchiveContract.VoicemailArchive._ID,
+                        VoicemailArchiveContract.VoicemailArchive.SERVER_ID
+                },
+                VoicemailArchiveContract.VoicemailArchive.SERVER_ID + "="
+                        + ContentUris.parseId(mVoicemailUri),
+                null,
+                null);
+    }
+
+    private int getRowServerId(Cursor cursor) {
+        return cursor
+                .getInt(cursor.getColumnIndex(VoicemailArchiveContract.VoicemailArchive.SERVER_ID));
+    }
+
+    private Uri getRowUri(Cursor cursor) {
+        return VoicemailArchiveContract.VoicemailArchive.buildWithId(cursor.getInt(
+                cursor.getColumnIndex(VoicemailArchiveContract.VoicemailArchive._ID)));
+    }
+
+    private boolean hasContent(Cursor cursor) {
+        return cursor != null && cursor.moveToFirst();
+    }
 }
\ No newline at end of file