Use the new DRM scheme in MMS

Bug 5158047

Change-Id: Id5d0ed03816b70c9f06b98af982cd5afb9af38d5
diff --git a/src/com/android/mms/MmsApp.java b/src/com/android/mms/MmsApp.java
index f02a42d..8eccfb8 100644
--- a/src/com/android/mms/MmsApp.java
+++ b/src/com/android/mms/MmsApp.java
@@ -20,6 +20,7 @@
 import android.app.Application;
 import android.content.Context;
 import android.content.res.Configuration;
+import android.drm.DrmManagerClient;
 import android.location.Country;
 import android.location.CountryDetector;
 import android.location.CountryListener;
@@ -31,7 +32,6 @@
 
 import com.android.mms.data.Contact;
 import com.android.mms.data.Conversation;
-import com.android.mms.drm.DrmUtils;
 import com.android.mms.layout.LayoutManager;
 import com.android.mms.transaction.MessagingNotification;
 import com.android.mms.util.DownloadManager;
@@ -52,6 +52,7 @@
     private static MmsApp sMmsApp = null;
     private PduLoaderManager mPduLoaderManager;
     private ThumbnailManager mThumbnailManager;
+    private DrmManagerClient mDrmManagerClient;
 
     @Override
     public void onCreate() {
@@ -83,7 +84,6 @@
         Conversation.init(this);
         DownloadManager.init(this);
         RateController.init(this);
-        DrmUtils.cleanupStorage(this);
         LayoutManager.init(this);
         SmileyParser.init(this);
         MessagingNotification.init(this);
@@ -105,7 +105,6 @@
 
     @Override
     public void onTerminate() {
-        DrmUtils.cleanupStorage(this);
         mCountryDetector.removeCountryListener(mCountryListener);
     }
 
@@ -158,4 +157,12 @@
     public String getCurrentCountryIso() {
         return mCountryIso;
     }
+
+    public DrmManagerClient getDrmManagerClient() {
+        if (mDrmManagerClient == null) {
+            mDrmManagerClient = new DrmManagerClient(getApplicationContext());
+        }
+        return mDrmManagerClient;
+    }
+
 }
diff --git a/src/com/android/mms/data/WorkingMessage.java b/src/com/android/mms/data/WorkingMessage.java
index 0bdd98f..2bad429 100755
--- a/src/com/android/mms/data/WorkingMessage.java
+++ b/src/com/android/mms/data/WorkingMessage.java
@@ -39,8 +39,6 @@
 
 import com.android.common.contacts.DataUsageStatUpdater;
 import com.android.common.userhappiness.UserHappinessSignals;
-
-import com.android.mms.ContentRestrictionException;
 import com.android.mms.ExceedMessageSizeException;
 import com.android.mms.LogTag;
 import com.android.mms.MmsConfig;
@@ -411,7 +409,7 @@
             int numSlides = mSlideshow.size();
             if (numSlides > 0) {
                 ImageModel imgModel = mSlideshow.get(numSlides - 1).getImage();
-                if (imgModel != null && !imgModel.isDrmProtected()) {
+                if (imgModel != null) {
                     cancelThumbnailLoading();
                     imgModel.loadThumbnailBitmap(null);
                 }
@@ -1104,7 +1102,7 @@
                 String err = "WorkingMessage.send MMS sending failure. mms_config.xml is " +
                         "missing uaProfUrl setting.  uaProfUrl is required for MMS service, " +
                         "but can be absent for SMS.";
-                RuntimeException ex = new ContentRestrictionException(err);
+                RuntimeException ex = new NullPointerException(err);
                 Log.e(TAG, err, ex);
                 // now, let's just crash.
                 throw ex;
diff --git a/src/com/android/mms/drm/DrmUtils.java b/src/com/android/mms/drm/DrmUtils.java
index 60701db..019487b 100644
--- a/src/com/android/mms/drm/DrmUtils.java
+++ b/src/com/android/mms/drm/DrmUtils.java
@@ -17,57 +17,67 @@
 
 package com.android.mms.drm;
 
-import android.database.sqlite.SqliteWrapper;
-
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.Context;
+import android.drm.*;
 import android.net.Uri;
 import android.util.Log;
 
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
 import java.io.IOException;
-import java.io.OutputStream;
+import java.io.RandomAccessFile;
+
+import com.android.mms.MmsApp;
 
 public class DrmUtils {
     private static final String TAG = "DrmUtils";
-    private static final Uri DRM_TEMP_URI = Uri.parse("content://mms/drm");
+
+    /** The MIME type of special DRM files */
+    private static final String EXTENSION_ANDROID_FWDL = ".fl";
 
     private DrmUtils() {
     }
 
-    public static void cleanupStorage(Context context) {
-        try {
-            SqliteWrapper.delete(context, context.getContentResolver(),
-                    DRM_TEMP_URI, null, null);
-        } catch (RuntimeException e) {
-            // If clearing the temp storage fails, that's not the end of the world; we'll just try
-            // again next time. Could potentially fail in the not-so-understood case described in
-            // b/5415438 (but in any case, we shouldn't kill the app if this fails).
-            Log.e(TAG, e.getMessage(), e);
-        }
+    public static String getConvertExtension(String mimetype) {
+        return EXTENSION_ANDROID_FWDL;
     }
 
-    public static Uri insert(Context context, DrmWrapper drmObj)
-            throws IOException {
-        ContentResolver cr = context.getContentResolver();
-        Uri uri = SqliteWrapper.insert(context, cr, DRM_TEMP_URI,
-                                       new ContentValues(0));
-        OutputStream os = null;
-        try {
-            os = cr.openOutputStream(uri);
-            byte[] data = drmObj.getDecryptedData();
-            if (data != null) {
-                os.write(data);
-            }
-            return uri;
-        } finally {
-            if (os != null) {
-                try {
-                    os.close();
-                } catch (IOException e) {
-                    Log.e(TAG, e.getMessage(), e);
+    public static boolean isDrmType(String mimeType) {
+        boolean result = false;
+        DrmManagerClient drmManagerClient = MmsApp.getApplication().getDrmManagerClient();
+        if (drmManagerClient != null) {
+            try {
+                if (drmManagerClient.canHandle("", mimeType)) {
+                    result = true;
                 }
+            } catch (IllegalArgumentException ex) {
+                Log.w(TAG, "canHandle called with wrong parameters");
+            } catch (IllegalStateException ex) {
+                Log.w(TAG, "DrmManagerClient didn't initialize properly");
             }
         }
+        return result;
+    }
+
+    /**
+     * Check if content may be forwarded according to DRM
+     *
+     * @param uri Uri to content
+     * @return true if the content may be forwarded
+     */
+    public static boolean haveRightsForAction(Uri uri, int action) {
+        DrmManagerClient drmManagerClient = MmsApp.getApplication().getDrmManagerClient();
+
+        try {
+            // first check if the URI is registered as DRM in DRM-framework
+            if (drmManagerClient.canHandle(uri.toString(), null)) {
+                int check = drmManagerClient.checkRightsStatus(uri.toString(), action);
+                return (check == DrmStore.RightsStatus.RIGHTS_VALID);
+            }
+        } catch (Exception e) {
+            // Ignore exception and assume it is OK to forward file.
+        } finally {
+        }
+        return true;
     }
 }
diff --git a/src/com/android/mms/drm/DrmWrapper.java b/src/com/android/mms/drm/DrmWrapper.java
deleted file mode 100644
index 164e3a2..0000000
--- a/src/com/android/mms/drm/DrmWrapper.java
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
- * Copyright (C) 2007-2008 Esmertec AG.
- * Copyright (C) 2007-2008 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.mms.drm;
-
-import com.google.android.mms.ContentType;
-
-import android.drm.mobile1.DrmException;
-import android.drm.mobile1.DrmRawContent;
-import android.drm.mobile1.DrmRights;
-import android.drm.mobile1.DrmRightsManager;
-import android.net.Uri;
-import android.util.Log;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * The Drm Wrapper.
- */
-public class DrmWrapper {
-    /**
-     * The DRM right object.
-     */
-    private DrmRights mRight;
-
-    /**
-     * The DrmRawContent.
-     */
-    private final DrmRawContent mDrmObject;
-
-    private final Uri mDataUri;
-    private final byte[] mData;
-    /**
-     * The decrypted data.
-     */
-    private byte[] mDecryptedData;
-
-    /**
-     * The log tag.
-     */
-    private static final String LOG_TAG = "DrmWrapper";
-    private static final boolean DEBUG = false;
-    private static final boolean LOCAL_LOGV = false;
-
-    /**
-     * Constructor.
-     * @param uri
-     */
-    public DrmWrapper(String drmContentType, Uri uri, byte[] drmData)
-            throws DrmException, IOException {
-        if ((drmContentType == null) || (drmData == null)) {
-            throw new IllegalArgumentException(
-                    "Content-Type or data may not be null.");
-        }
-
-        mDataUri = uri;
-        mData = drmData;
-
-        ByteArrayInputStream drmDataStream = new ByteArrayInputStream(drmData);
-        mDrmObject = new DrmRawContent(drmDataStream, drmDataStream.available(),
-                                       drmContentType);
-        // Install rights if necessary.
-        if (!isRightsInstalled()) {
-            if (LOCAL_LOGV) {
-                Log.v(LOG_TAG, "DRM rights not installed yet.");
-            }
-            installRights(drmData);
-        }
-    }
-
-    /**
-     * Get permission type for the decrypted content-type.
-     *
-     * @return the permission
-     */
-    private int getPermission() {
-        String contentType = mDrmObject.getContentType();
-
-        if (ContentType.isAudioType(contentType) ||
-                ContentType.isVideoType(contentType)) {
-            return DrmRights.DRM_PERMISSION_PLAY;
-        }
-        return DrmRights.DRM_PERMISSION_DISPLAY;
-    }
-
-    /**
-     * Get decrypted data.
-     *
-     * @return the decrypted content if decryption was successful.
-     * @throws IOException
-     */
-    public byte[] getDecryptedData() throws IOException {
-        if ((mDecryptedData == null) && (mRight != null)) {
-            // Decrypt it.
-            InputStream decryptedDataStream = mDrmObject.getContentInputStream(mRight);
-            try {
-                ByteArrayOutputStream baos = new ByteArrayOutputStream();
-                byte[] buffer = new byte[256];
-                int len;
-                while ((len = decryptedDataStream.read(buffer)) > 0) {
-                    baos.write(buffer, 0, len);
-                }
-                mDecryptedData = baos.toByteArray();
-            } finally {
-                try {
-                    decryptedDataStream.close();
-                } catch (IOException e) {
-                    Log.e(LOG_TAG, e.getMessage(), e);
-                }
-            }
-        }
-
-        if (mDecryptedData != null) {
-            byte[] decryptedData = new byte[mDecryptedData.length];
-            System.arraycopy(mDecryptedData, 0, decryptedData, 0, mDecryptedData.length);
-            return decryptedData;
-        }
-        return null;
-    }
-
-    /**
-     * Consume the rights.
-     *
-     * @return true if consume success
-     *         false if consume failure
-     */
-    public boolean consumeRights() {
-        if (mRight == null) {
-            return false;
-        }
-
-        return mRight.consumeRights(getPermission());
-    }
-
-    /**
-     * Install Right.
-     *
-     * @param rightData right's data
-     * @throws IOException
-     * @throws DrmException
-     */
-    public void installRights(byte[] rightData) throws DrmException, IOException {
-        if (rightData == null) {
-            throw new DrmException("Right data may not be null.");
-        }
-
-        if (LOCAL_LOGV) {
-            Log.v(LOG_TAG, "Installing DRM rights.");
-        }
-
-        ByteArrayInputStream rightDataStream = new ByteArrayInputStream(rightData);
-        mRight = DrmRightsManager.getInstance().installRights(
-                rightDataStream, rightData.length,
-                DrmRawContent.DRM_MIMETYPE_MESSAGE_STRING);
-    }
-
-    /**
-     * Check whether the DRM object's right is existed. If not, we should
-     * download it.
-     *
-     * @return true if it is existed
-     *         false if not
-     */
-    public boolean isRightsInstalled() {
-        if (mRight != null) {
-            return true;
-        }
-
-        mRight = DrmRightsManager.getInstance().queryRights(mDrmObject);
-        return mRight != null ? true : false;
-    }
-
-    /**
-     * Check whether this DRM object can be forwarded.
-     *
-     * @return true if this object can be forwarded
-     *         false if not
-     */
-    public boolean isAllowedToForward() {
-        if (DrmRawContent.DRM_SEPARATE_DELIVERY != mDrmObject.getRawType()) {
-            return false;
-        }
-        return true;
-    }
-
-    /**
-     * Get URL of right.
-     *
-     * @return the right's URL
-     */
-    public String getRightsAddress() {
-        if (mDrmObject == null) {
-            return null;
-        }
-        return mDrmObject.getRightsAddress();
-    }
-
-    /**
-     * Get the decrypted object's content-type.
-     *
-     * @return the content-type
-     */
-    public String getContentType() {
-        return mDrmObject.getContentType();
-    }
-
-    public Uri getOriginalUri() {
-        return mDataUri;
-    }
-
-    public byte[] getOriginalData() {
-        return mData;
-    }
-}
diff --git a/src/com/android/mms/model/AudioModel.java b/src/com/android/mms/model/AudioModel.java
index f0fa252..b1fe051 100644
--- a/src/com/android/mms/model/AudioModel.java
+++ b/src/com/android/mms/model/AudioModel.java
@@ -20,7 +20,6 @@
 import com.android.mms.ContentRestrictionException;
 import com.android.mms.dom.events.EventImpl;
 import com.android.mms.dom.smil.SmilMediaElementImpl;
-import com.android.mms.drm.DrmWrapper;
 import com.google.android.mms.MmsException;
 import android.database.sqlite.SqliteWrapper;
 
@@ -57,12 +56,6 @@
         mExtras = new HashMap<String, String>();
     }
 
-    public AudioModel(Context context, String contentType, String src,
-            DrmWrapper wrapper) throws IOException {
-        super(context, SmilHelper.ELEMENT_TAG_AUDIO, contentType, src, wrapper);
-        mExtras = new HashMap<String, String>();
-    }
-
     private void initModelFromUri(Uri uri) throws MmsException {
         ContentResolver cr = mContext.getContentResolver();
         Cursor c = SqliteWrapper.query(mContext, cr, uri, null, null, null, null);
diff --git a/src/com/android/mms/model/ImageModel.java b/src/com/android/mms/model/ImageModel.java
index 4dea308..40810aa 100644
--- a/src/com/android/mms/model/ImageModel.java
+++ b/src/com/android/mms/model/ImageModel.java
@@ -23,8 +23,6 @@
 import com.android.mms.MmsApp;
 import com.android.mms.MmsConfig;
 import com.android.mms.dom.smil.SmilMediaElementImpl;
-import android.drm.mobile1.DrmException;
-import com.android.mms.drm.DrmWrapper;
 import com.android.mms.ui.UriImage;
 import com.android.mms.util.ItemLoadedCallback;
 import com.android.mms.util.ItemLoadedFuture;
@@ -52,7 +50,6 @@
 
 
 public class ImageModel extends RegionMediaModel {
-    @SuppressWarnings("hiding")
     private static final String TAG = "Mms/image";
     private static final boolean DEBUG = false;
     private static final boolean LOCAL_LOGV = false;
@@ -81,16 +78,10 @@
     }
 
     public ImageModel(Context context, String contentType, String src,
-            Uri uri, RegionModel region) throws DrmException, MmsException {
+            Uri uri, RegionModel region) throws MmsException {
         super(context, SmilHelper.ELEMENT_TAG_IMAGE,
                 contentType, src, uri, region);
-        decodeImageBounds();
-    }
-
-    public ImageModel(Context context, String contentType, String src,
-            DrmWrapper wrapper, RegionModel regionModel) throws IOException {
-        super(context, SmilHelper.ELEMENT_TAG_IMAGE, contentType, src,
-                wrapper, regionModel);
+        decodeImageBounds(uri);
     }
 
     private void initModelFromUri(Uri uri) throws MmsException {
@@ -112,8 +103,8 @@
         }
     }
 
-    private void decodeImageBounds() throws DrmException {
-        UriImage uriImage = new UriImage(mContext, getUriWithDrmCheck());
+    private void decodeImageBounds(Uri uri) {
+        UriImage uriImage = new UriImage(mContext, uri);
         mWidth = uriImage.getWidth();
         mHeight = uriImage.getHeight();
 
@@ -163,12 +154,20 @@
         }
     }
 
-    public Bitmap getBitmapWithDrmCheck(int width, int height) throws DrmException {
-        Uri uri = getUriWithDrmCheck();     // will throw exception if no drm rights
+    private Bitmap createBitmap(int thumbnailBoundsLimit, Uri uri) {
+        byte[] data = UriImage.getResizedImageData(mWidth, mHeight,
+                thumbnailBoundsLimit, thumbnailBoundsLimit, PICTURE_SIZE_LIMIT, uri, mContext);
+        if (LOCAL_LOGV) {
+            Log.v(TAG, "createBitmap size: " + (data == null ? data : data.length));
+        }
+        return data == null ? null : BitmapFactory.decodeByteArray(data, 0, data.length);
+    }
+
+    public Bitmap getBitmap(int width, int height)  {
         Bitmap bm = mFullSizeBitmapCache.get();
         if (bm == null) {
             try {
-                bm = createBitmap(Math.max(width, height), uri);
+                bm = createBitmap(Math.max(width, height), getUri());
                 if (bm != null) {
                     mFullSizeBitmapCache = new SoftReference<Bitmap>(bm);
                 }
@@ -180,15 +179,6 @@
         return bm;
     }
 
-    private Bitmap createBitmap(int thumbnailBoundsLimit, Uri uri) {
-        byte[] data = UriImage.getResizedImageData(mWidth, mHeight,
-                thumbnailBoundsLimit, thumbnailBoundsLimit, PICTURE_SIZE_LIMIT, uri, mContext);
-        if (LOCAL_LOGV) {
-            Log.v(TAG, "createBitmap size: " + (data == null ? data : data.length));
-        }
-        return data == null ? null : BitmapFactory.decodeByteArray(data, 0, data.length);
-    }
-
     @Override
     public boolean getMediaResizable() {
         return true;
diff --git a/src/com/android/mms/model/LayoutModel.java b/src/com/android/mms/model/LayoutModel.java
index 7ef6813..e52b65c 100644
--- a/src/com/android/mms/model/LayoutModel.java
+++ b/src/com/android/mms/model/LayoutModel.java
@@ -20,6 +20,7 @@
 import com.android.mms.layout.LayoutManager;
 import com.android.mms.layout.LayoutParameters;
 
+import android.util.Config;
 import android.util.Log;
 
 import java.util.ArrayList;
@@ -27,7 +28,7 @@
 public class LayoutModel extends Model {
     private static final String TAG = SlideModel.TAG;
     private static final boolean DEBUG = false;
-    private static final boolean LOCAL_LOGV = false;
+    private static final boolean LOCAL_LOGV = DEBUG ? Config.LOGD : Config.LOGV;
 
     public static final String IMAGE_REGION_ID = "Image";
     public static final String TEXT_REGION_ID  = "Text";
diff --git a/src/com/android/mms/model/MediaModel.java b/src/com/android/mms/model/MediaModel.java
index 79f991e..452d361 100644
--- a/src/com/android/mms/model/MediaModel.java
+++ b/src/com/android/mms/model/MediaModel.java
@@ -19,11 +19,8 @@
 
 import com.android.mms.R;
 import com.android.mms.LogTag;
-import android.drm.mobile1.DrmException;
-import com.android.mms.drm.DrmWrapper;
 import android.media.MediaMetadataRetriever;        // TODO: remove dependency for SDK build
 import com.google.android.mms.MmsException;
-import com.android.mms.drm.DrmUtils;
 
 import org.w3c.dom.events.EventListener;
 
@@ -55,7 +52,6 @@
     protected short mFill;
     protected int mSize;
     protected int mSeekTo;
-    protected DrmWrapper mDrmObjectWrapper;
     protected boolean mMediaResizeable;
 
     private final ArrayList<MediaAction> mMediaActions;
@@ -93,18 +89,6 @@
         mMediaActions = new ArrayList<MediaAction>();
     }
 
-    public MediaModel(Context context, String tag, String contentType,
-            String src, DrmWrapper wrapper) throws IOException {
-        mContext = context;
-        mTag = tag;
-        mContentType = contentType;
-        mSrc = src;
-        mDrmObjectWrapper = wrapper;
-        mUri = DrmUtils.insert(context, wrapper);
-        mSize = wrapper.getOriginalData().length;
-        mMediaActions = new ArrayList<MediaAction>();
-    }
-
     public int getBegin() {
         return mBegin;
     }
@@ -143,8 +127,7 @@
     }
 
     /**
-     * Get the URI of the media without checking DRM rights. Use this method
-     * only if the media is NOT DRM protected.
+     * Get the URI of the media.
      *
      * @return The URI of the media.
      */
@@ -152,29 +135,8 @@
         return mUri;
     }
 
-    /**
-     * Get the URI of the media with checking DRM rights. Use this method
-     * if the media is probably DRM protected.
-     *
-     * @return The URI of the media.
-     * @throws DrmException Insufficient DRM rights detected.
-     */
-    public Uri getUriWithDrmCheck() throws DrmException {
-        if (mUri != null) {
-            if (isDrmProtected() && !mDrmObjectWrapper.consumeRights()) {
-                throw new DrmException("Insufficient DRM rights.");
-            }
-        }
-        return mUri;
-    }
-
-    public byte[] getData() throws DrmException {
+    public byte[] getData() {
         if (mData != null) {
-            if (isDrmProtected() && !mDrmObjectWrapper.consumeRights()) {
-                throw new DrmException(
-                        mContext.getString(R.string.insufficient_drm_rights));
-            }
-
             byte[] data = new byte[mData.length];
             System.arraycopy(mData, 0, data, 0, mData.length);
             return data;
@@ -243,14 +205,6 @@
         return mTag.equals(SmilHelper.ELEMENT_TAG_AUDIO);
     }
 
-    public boolean isDrmProtected() {
-        return mDrmObjectWrapper != null;
-    }
-
-    public boolean isAllowedToForward() {
-        return mDrmObjectWrapper.isAllowedToForward();
-    }
-
     protected void initMediaDuration() throws MmsException {
         if (mUri == null) {
             throw new IllegalArgumentException("Uri may not be null.");
@@ -332,10 +286,6 @@
         return false;
     }
 
-    public DrmWrapper getDrmObject() {
-        return mDrmObjectWrapper;
-    }
-
     protected void pauseMusicPlayer() {
         if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) {
             Log.d(TAG, "pauseMusicPlayer");
diff --git a/src/com/android/mms/model/MediaModelFactory.java b/src/com/android/mms/model/MediaModelFactory.java
index bd0ff63..9928395 100644
--- a/src/com/android/mms/model/MediaModelFactory.java
+++ b/src/com/android/mms/model/MediaModelFactory.java
@@ -20,8 +20,6 @@
 import com.android.mms.UnsupportContentTypeException;
 import com.android.mms.LogTag;
 import com.android.mms.MmsConfig;
-import android.drm.mobile1.DrmException;
-import com.android.mms.drm.DrmWrapper;
 import com.google.android.mms.ContentType;
 import com.google.android.mms.MmsException;
 import com.google.android.mms.pdu.CharacterSets;
@@ -44,7 +42,7 @@
 
     public static MediaModel getMediaModel(Context context,
             SMILMediaElement sme, LayoutModel layouts, PduBody pb)
-            throws DrmException, IOException, IllegalArgumentException, MmsException {
+            throws IOException, IllegalArgumentException, MmsException {
         String tag = sme.getTagName();
         String src = sme.getSrc();
         PduPart part = findPart(pb, src);
@@ -93,7 +91,7 @@
 
     private static MediaModel getRegionMediaModel(Context context,
             String tag, String src, SMILRegionMediaElement srme,
-            LayoutModel layouts, PduPart part) throws DrmException, IOException, MmsException {
+            LayoutModel layouts, PduPart part) throws IOException, MmsException {
         SMILRegionElement sre = srme.getRegion();
         if (sre != null) {
             RegionModel region = layouts.findRegionById(sre.getId());
@@ -120,17 +118,14 @@
 
     // When we encounter a content type we can't handle, such as "application/vnd.smaf", instead
     // of throwing an exception and crashing, insert an empty TextModel in its place.
-    private static MediaModel createEmptyTextModel(Context context, DrmWrapper wrapper,
-            RegionModel regionModel) throws IOException {
-        return wrapper != null ?
-                new TextModel(context, ContentType.TEXT_PLAIN, null, CharacterSets.ANY_CHARSET,
-                        wrapper, regionModel) :
-                new TextModel(context, ContentType.TEXT_PLAIN, null, regionModel);
+    private static MediaModel createEmptyTextModel(Context context,  RegionModel regionModel)
+            throws IOException {
+        return new TextModel(context, ContentType.TEXT_PLAIN, null, regionModel);
     }
 
     private static MediaModel getGenericMediaModel(Context context,
             String tag, String src, SMILMediaElement sme, PduPart part,
-            RegionModel regionModel) throws DrmException, IOException, MmsException {
+            RegionModel regionModel) throws IOException, MmsException {
         byte[] bytes = part.getContentType();
         if (bytes == null) {
             throw new IllegalArgumentException(
@@ -139,77 +134,38 @@
 
         String contentType = new String(bytes);
         MediaModel media = null;
-        if (ContentType.isDrmType(contentType)) {
-            DrmWrapper wrapper = new DrmWrapper(
-                    contentType, part.getDataUri(), part.getData());
-            if (tag.equals(SmilHelper.ELEMENT_TAG_TEXT)) {
-                media = new TextModel(context, contentType, src,
-                        part.getCharset(), wrapper, regionModel);
-            } else if (tag.equals(SmilHelper.ELEMENT_TAG_IMAGE)) {
-                media = new ImageModel(context, contentType, src,
-                        wrapper, regionModel);
-            } else if (tag.equals(SmilHelper.ELEMENT_TAG_VIDEO)) {
-                media = new VideoModel(context, contentType, src,
-                        wrapper, regionModel);
-            } else if (tag.equals(SmilHelper.ELEMENT_TAG_AUDIO)) {
-                media = new AudioModel(context, contentType, src,
-                        wrapper);
-            } else if (tag.equals(SmilHelper.ELEMENT_TAG_REF)) {
-                String drmContentType = wrapper.getContentType();
-                if (ContentType.isTextType(drmContentType)) {
-                    media = new TextModel(context, contentType, src,
-                            part.getCharset(), wrapper, regionModel);
-                } else if (ContentType.isImageType(drmContentType)) {
-                    media = new ImageModel(context, contentType, src,
-                            wrapper, regionModel);
-                } else if (ContentType.isVideoType(drmContentType)) {
-                    media = new VideoModel(context, contentType, src,
-                            wrapper, regionModel);
-                } else if (ContentType.isAudioType(drmContentType)) {
-                    media = new AudioModel(context, contentType, src,
-                            wrapper);
-                } else {
-                    Log.d(TAG, "[MediaModelFactory] getGenericMediaModel Unsupported Content-Type: "
-                            + contentType);
-                    media = createEmptyTextModel(context, wrapper, regionModel);
-                }
-            } else {
-                throw new IllegalArgumentException("Unsupported TAG: " + tag);
-            }
-        } else {
-            if (tag.equals(SmilHelper.ELEMENT_TAG_TEXT)) {
+        if (tag.equals(SmilHelper.ELEMENT_TAG_TEXT)) {
+            media = new TextModel(context, contentType, src,
+                    part.getCharset(), part.getData(), regionModel);
+        } else if (tag.equals(SmilHelper.ELEMENT_TAG_IMAGE)) {
+            media = new ImageModel(context, contentType, src,
+                    part.getDataUri(), regionModel);
+        } else if (tag.equals(SmilHelper.ELEMENT_TAG_VIDEO)) {
+            media = new VideoModel(context, contentType, src,
+                    part.getDataUri(), regionModel);
+        } else if (tag.equals(SmilHelper.ELEMENT_TAG_AUDIO)) {
+            media = new AudioModel(context, contentType, src,
+                    part.getDataUri());
+        } else if (tag.equals(SmilHelper.ELEMENT_TAG_REF)) {
+            if (ContentType.isTextType(contentType)) {
                 media = new TextModel(context, contentType, src,
                         part.getCharset(), part.getData(), regionModel);
-            } else if (tag.equals(SmilHelper.ELEMENT_TAG_IMAGE)) {
+            } else if (ContentType.isImageType(contentType)) {
                 media = new ImageModel(context, contentType, src,
                         part.getDataUri(), regionModel);
-            } else if (tag.equals(SmilHelper.ELEMENT_TAG_VIDEO)) {
+            } else if (ContentType.isVideoType(contentType)) {
                 media = new VideoModel(context, contentType, src,
                         part.getDataUri(), regionModel);
-            } else if (tag.equals(SmilHelper.ELEMENT_TAG_AUDIO)) {
+            } else if (ContentType.isAudioType(contentType)) {
                 media = new AudioModel(context, contentType, src,
                         part.getDataUri());
-            } else if (tag.equals(SmilHelper.ELEMENT_TAG_REF)) {
-                if (ContentType.isTextType(contentType)) {
-                    media = new TextModel(context, contentType, src,
-                            part.getCharset(), part.getData(), regionModel);
-                } else if (ContentType.isImageType(contentType)) {
-                    media = new ImageModel(context, contentType, src,
-                            part.getDataUri(), regionModel);
-                } else if (ContentType.isVideoType(contentType)) {
-                    media = new VideoModel(context, contentType, src,
-                            part.getDataUri(), regionModel);
-                } else if (ContentType.isAudioType(contentType)) {
-                    media = new AudioModel(context, contentType, src,
-                            part.getDataUri());
-                } else {
-                    Log.d(TAG, "[MediaModelFactory] getGenericMediaModel Unsupported Content-Type: "
-                            + contentType);
-                    media = createEmptyTextModel(context, null, regionModel);
-                }
             } else {
-                throw new IllegalArgumentException("Unsupported TAG: " + tag);
+                Log.d(TAG, "[MediaModelFactory] getGenericMediaModel Unsupported Content-Type: "
+                        + contentType);
+                media = createEmptyTextModel(context, regionModel);
             }
+        } else {
+            throw new IllegalArgumentException("Unsupported TAG: " + tag);
         }
 
         // Set 'begin' property.
diff --git a/src/com/android/mms/model/RegionMediaModel.java b/src/com/android/mms/model/RegionMediaModel.java
index 2173d4c..8bbb06b 100644
--- a/src/com/android/mms/model/RegionMediaModel.java
+++ b/src/com/android/mms/model/RegionMediaModel.java
@@ -17,8 +17,6 @@
 
 package com.android.mms.model;
 
-import com.android.mms.drm.DrmWrapper;
-
 import com.google.android.mms.MmsException;
 
 import android.content.Context;
@@ -47,13 +45,6 @@
         mRegion = region;
     }
 
-    public RegionMediaModel(Context context, String tag, String contentType,
-            String src, DrmWrapper wrapper, RegionModel region)
-            throws IOException {
-        super(context, tag, contentType, src, wrapper);
-        mRegion = region;
-    }
-
     public RegionModel getRegion() {
         return mRegion;
     }
diff --git a/src/com/android/mms/model/SlideModel.java b/src/com/android/mms/model/SlideModel.java
index 01a69bb..3c8d70b 100644
--- a/src/com/android/mms/model/SlideModel.java
+++ b/src/com/android/mms/model/SlideModel.java
@@ -25,6 +25,7 @@
 import org.w3c.dom.events.EventListener;
 import org.w3c.dom.smil.ElementTime;
 
+import android.util.Config;
 import android.util.Log;
 import android.text.TextUtils;
 
@@ -37,7 +38,7 @@
 public class SlideModel extends Model implements List<MediaModel>, EventListener {
     public static final String TAG = "Mms/slideshow";
     private static final boolean DEBUG = false;
-    private static final boolean LOCAL_LOGV = false;
+    private static final boolean LOCAL_LOGV = DEBUG ? Config.LOGD : Config.LOGV;
     private static final int DEFAULT_SLIDE_DURATION = 5000;
 
     private final ArrayList<MediaModel> mMedia = new ArrayList<MediaModel>();
diff --git a/src/com/android/mms/model/SlideshowModel.java b/src/com/android/mms/model/SlideshowModel.java
index 8fda49f..e2ecb0d 100755
--- a/src/com/android/mms/model/SlideshowModel.java
+++ b/src/com/android/mms/model/SlideshowModel.java
@@ -24,8 +24,6 @@
 import com.android.mms.MmsConfig;
 import com.android.mms.R;
 import com.android.mms.dom.smil.parser.SmilXmlSerializer;
-import android.drm.mobile1.DrmException;
-import com.android.mms.drm.DrmWrapper;
 import com.android.mms.layout.LayoutManager;
 import com.google.android.mms.ContentType;
 import com.google.android.mms.MmsException;
@@ -210,8 +208,6 @@
                             (EventTarget) sme, media);
                     mediaSet.add(media);
                     totalMessageSize += media.getMediaSize();
-                } catch (DrmException e) {
-                    Log.e(TAG, e.getMessage(), e);
                 } catch (IOException e) {
                     Log.e(TAG, e.getMessage(), e);
                 } catch (IllegalArgumentException e) {
@@ -240,22 +236,11 @@
     }
 
     private PduBody makePduBody(SMILDocument document) {
-        return makePduBody(null, document, false);
-    }
-
-    private PduBody makePduBody(Context context, SMILDocument document, boolean isMakingCopy) {
         PduBody pb = new PduBody();
 
         boolean hasForwardLock = false;
         for (SlideModel slide : mSlides) {
             for (MediaModel media : slide) {
-                if (isMakingCopy) {
-                    if (media.isDrmProtected() && !media.isAllowedToForward()) {
-                        hasForwardLock = true;
-                        continue;
-                    }
-                }
-
                 PduPart part = new PduPart();
 
                 if (media.isText()) {
@@ -295,11 +280,7 @@
                     part.setContentId(contentId.getBytes());
                 }
 
-                if (media.isDrmProtected()) {
-                    DrmWrapper wrapper = media.getDrmObject();
-                    part.setDataUri(wrapper.getOriginalUri());
-                    part.setData(wrapper.getOriginalData());
-                } else if (media.isText()) {
+                if (media.isText()) {
                     part.setData(((TextModel) media).getText().getBytes());
                 } else if (media.isImage() || media.isVideo() || media.isAudio()) {
                     part.setDataUri(media.getUri());
@@ -311,13 +292,6 @@
             }
         }
 
-        if (hasForwardLock && isMakingCopy && context != null) {
-            Toast.makeText(context,
-                    context.getString(R.string.cannot_forward_drm_obj),
-                    Toast.LENGTH_LONG).show();
-            document = SmilHelper.getDocument(pb);
-        }
-
         // Create and insert SMIL part(as the first part) into the PduBody.
         ByteArrayOutputStream out = new ByteArrayOutputStream();
         SmilXmlSerializer.serialize(document, out);
@@ -331,8 +305,8 @@
         return pb;
     }
 
-    public PduBody makeCopy(Context context) {
-        return makePduBody(context, SmilHelper.getDocument(this), true);
+    public PduBody makeCopy() {
+        return makePduBody(SmilHelper.getDocument(this));
     }
 
     public SMILDocument toSmilDocument() {
diff --git a/src/com/android/mms/model/SmilHelper.java b/src/com/android/mms/model/SmilHelper.java
index d2a1c29..577ba5a 100644
--- a/src/com/android/mms/model/SmilHelper.java
+++ b/src/com/android/mms/model/SmilHelper.java
@@ -24,11 +24,11 @@
 import static com.android.mms.dom.smil.SmilParElementImpl.SMIL_SLIDE_END_EVENT;
 import static com.android.mms.dom.smil.SmilParElementImpl.SMIL_SLIDE_START_EVENT;
 
+import com.android.mms.MmsApp;
 import com.android.mms.dom.smil.SmilDocumentImpl;
 import com.android.mms.dom.smil.parser.SmilXmlParser;
 import com.android.mms.dom.smil.parser.SmilXmlSerializer;
-import android.drm.mobile1.DrmException;
-import com.android.mms.drm.DrmWrapper;
+import com.android.mms.drm.DrmUtils;
 import com.google.android.mms.ContentType;
 import com.google.android.mms.MmsException;
 import com.google.android.mms.pdu.PduBody;
@@ -45,11 +45,19 @@
 import org.w3c.dom.smil.SMILRootLayoutElement;
 import org.xml.sax.SAXException;
 
+import android.content.ContentResolver;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteException;
+import android.drm.DrmManagerClient;
+import android.net.Uri;
+import android.provider.MediaStore;
 import android.text.TextUtils;
+import android.util.Config;
 import android.util.Log;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
+import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -57,7 +65,7 @@
 public class SmilHelper {
     private static final String TAG = "Mms/smil";
     private static final boolean DEBUG = false;
-    private static final boolean LOCAL_LOGV = false;
+    private static final boolean LOCAL_LOGV = DEBUG ? Config.LOGD : Config.LOGV;
 
     public static final String ELEMENT_TAG_TEXT = "text";
     public static final String ELEMENT_TAG_IMAGE = "img";
@@ -167,7 +175,7 @@
     }
 
     private static SMILDocument createSmilDocument(PduBody pb) {
-        if (false) {
+        if (Config.LOGV) {
             Log.v(TAG, "Creating default SMIL document.");
         }
 
@@ -197,6 +205,8 @@
             return document;
         }
 
+        DrmManagerClient drmManagerClient = MmsApp.getApplication().getDrmManagerClient();
+
         boolean hasText = false;
         boolean hasMedia = false;
         for (int i = 0; i < partsNum; i++) {
@@ -209,17 +219,9 @@
 
             PduPart part = pb.getPart(i);
             String contentType = new String(part.getContentType());
+
             if (ContentType.isDrmType(contentType)) {
-                DrmWrapper dw;
-                try {
-                    dw = new DrmWrapper(contentType, part.getDataUri(),
-                                        part.getData());
-                    contentType = dw.getContentType();
-                } catch (DrmException e) {
-                    Log.e(TAG, e.getMessage(), e);
-                } catch (IOException e) {
-                    Log.e(TAG, e.getMessage(), e);
-                }
+                contentType = drmManagerClient.getOriginalMimeType(part.getDataUri());
             }
 
             if (contentType.equals(ContentType.TEXT_PLAIN)
@@ -254,7 +256,7 @@
     }
 
     private static SMILDocument createSmilDocument(SlideshowModel slideshow) {
-        if (false) {
+        if (Config.LOGV) {
             Log.v(TAG, "Creating SMIL document from SlideshowModel.");
         }
 
diff --git a/src/com/android/mms/model/TextModel.java b/src/com/android/mms/model/TextModel.java
index 8df8f29..a63be87 100644
--- a/src/com/android/mms/model/TextModel.java
+++ b/src/com/android/mms/model/TextModel.java
@@ -18,8 +18,6 @@
 package com.android.mms.model;
 
 import com.android.mms.dom.smil.SmilMediaElementImpl;
-import android.drm.mobile1.DrmException;
-import com.android.mms.drm.DrmWrapper;
 import com.google.android.mms.pdu.CharacterSets;
 
 import org.w3c.dom.events.Event;
@@ -72,27 +70,9 @@
         return "";
     }
 
-    public TextModel(Context context, String contentType, String src, int charset,
-            DrmWrapper wrapper, RegionModel regionModel) throws IOException {
-        super(context, SmilHelper.ELEMENT_TAG_TEXT, contentType, src, wrapper, regionModel);
-
-        if (charset == CharacterSets.ANY_CHARSET) {
-            // By default, we use ISO_8859_1 to decode the data
-            // which character set wasn't set.
-            charset = CharacterSets.ISO_8859_1;
-        }
-        mCharset = charset;
-    }
-
     public String getText() {
         if (mText == null) {
-            try {
-                mText = extractTextFromData(getData());
-            } catch (DrmException e) {
-                Log.e(TAG, e.getMessage(), e);
-                // Display DRM error message in place.
-                mText = e.getMessage();
-            }
+            mText = extractTextFromData(getData());
         }
 
         // If our internal CharSequence is not already a String,
diff --git a/src/com/android/mms/model/VideoModel.java b/src/com/android/mms/model/VideoModel.java
index b57e065..75d5c5d 100644
--- a/src/com/android/mms/model/VideoModel.java
+++ b/src/com/android/mms/model/VideoModel.java
@@ -22,7 +22,6 @@
 import com.android.mms.MmsApp;
 import com.android.mms.dom.events.EventImpl;
 import com.android.mms.dom.smil.SmilMediaElementImpl;
-import com.android.mms.drm.DrmWrapper;
 import com.android.mms.util.ItemLoadedCallback;
 import com.android.mms.util.ItemLoadedFuture;
 import com.android.mms.util.ThumbnailManager;
@@ -62,11 +61,6 @@
         super(context, SmilHelper.ELEMENT_TAG_VIDEO, contentType, src, uri, region);
     }
 
-    public VideoModel(Context context, String contentType, String src,
-            DrmWrapper wrapper, RegionModel regionModel) throws IOException {
-        super(context, SmilHelper.ELEMENT_TAG_VIDEO, contentType, src, wrapper, regionModel);
-    }
-
     private void initModelFromUri(Uri uri) throws MmsException {
         String scheme = uri.getScheme();
         if (scheme.equals("content")) {
diff --git a/src/com/android/mms/transaction/DefaultRetryScheme.java b/src/com/android/mms/transaction/DefaultRetryScheme.java
index cf5253b..1fe11d6 100644
--- a/src/com/android/mms/transaction/DefaultRetryScheme.java
+++ b/src/com/android/mms/transaction/DefaultRetryScheme.java
@@ -18,6 +18,7 @@
 package com.android.mms.transaction;
 
 import android.content.Context;
+import android.util.Config;
 import android.util.Log;
 
 /**
@@ -26,7 +27,7 @@
 public class DefaultRetryScheme extends AbstractRetryScheme {
     private static final String TAG = "DefaultRetryScheme";
     private static final boolean DEBUG = false;
-    private static final boolean LOCAL_LOGV = false;
+    private static final boolean LOCAL_LOGV = DEBUG ? Config.LOGD : Config.LOGV;
 
     private static final int[] sDefaultRetryScheme = {
         0, 1 * 60 * 1000, 5 * 60 * 1000, 10 * 60 * 1000, 30 * 60 * 1000};
diff --git a/src/com/android/mms/transaction/HttpUtils.java b/src/com/android/mms/transaction/HttpUtils.java
index 8726238..832f306 100644
--- a/src/com/android/mms/transaction/HttpUtils.java
+++ b/src/com/android/mms/transaction/HttpUtils.java
@@ -52,6 +52,9 @@
 public class HttpUtils {
     private static final String TAG = LogTag.TRANSACTION;
 
+    private static final boolean DEBUG = false;
+    private static final boolean LOCAL_LOGV = DEBUG ? Config.LOGD : Config.LOGV;
+
     public static final int HTTP_POST_METHOD = 1;
     public static final int HTTP_GET_METHOD = 2;
 
diff --git a/src/com/android/mms/ui/ComposeMessageActivity.java b/src/com/android/mms/ui/ComposeMessageActivity.java
index a5109fb..4df9457 100644
--- a/src/com/android/mms/ui/ComposeMessageActivity.java
+++ b/src/com/android/mms/ui/ComposeMessageActivity.java
@@ -62,6 +62,8 @@
 import android.database.Cursor;
 import android.database.sqlite.SQLiteException;
 import android.database.sqlite.SqliteWrapper;
+import android.drm.DrmManagerClient;
+import android.drm.DrmStore;
 import android.drm.mobile1.DrmException;
 import android.drm.mobile1.DrmRawContent;
 import android.graphics.drawable.Drawable;
@@ -77,7 +79,6 @@
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.CommonDataKinds.Email;
 import android.provider.ContactsContract.Contacts;
-import android.provider.DrmStore;
 import android.provider.MediaStore;
 import android.provider.Settings;
 import android.provider.ContactsContract.Intents;
@@ -133,6 +134,7 @@
 import com.android.mms.data.Conversation;
 import com.android.mms.data.WorkingMessage;
 import com.android.mms.data.WorkingMessage.MessageStatusListener;
+import com.android.mms.drm.DrmUtils;
 import com.google.android.mms.ContentType;
 import com.google.android.mms.pdu.EncodedStringValue;
 import com.google.android.mms.MmsException;
@@ -140,6 +142,7 @@
 import com.google.android.mms.pdu.PduPart;
 import com.google.android.mms.pdu.PduPersister;
 import com.google.android.mms.pdu.SendReq;
+import com.google.android.mms.util.DownloadDrmHelper;
 import com.google.android.mms.util.PduCache;
 import com.android.mms.model.SlideModel;
 import com.android.mms.model.SlideshowModel;
@@ -215,7 +218,7 @@
     private static final int MENU_ADD_ADDRESS_TO_CONTACTS = 27;
     private static final int MENU_LOCK_MESSAGE          = 28;
     private static final int MENU_UNLOCK_MESSAGE        = 29;
-    private static final int MENU_COPY_TO_DRM_PROVIDER  = 30;
+    private static final int MENU_SAVE_RINGTONE         = 30;
     private static final int MENU_PREFERENCES           = 31;
 
     private static final int RECIPIENTS_MAX_LENGTH = 312;
@@ -924,7 +927,7 @@
             addCallAndContactMenuItems(menu, l, msgItem);
 
             // Forward is not available for undownloaded messages.
-            if (msgItem.isDownloaded()) {
+            if (msgItem.isDownloaded() && isForwardable(msgId)) {
                 menu.add(0, MENU_FORWARD_MESSAGE, 0, R.string.menu_forward)
                         .setOnMenuItemClickListener(l);
             }
@@ -961,8 +964,8 @@
                             menu.add(0, MENU_COPY_TO_SDCARD, 0, R.string.copy_to_sdcard)
                             .setOnMenuItemClickListener(l);
                         }
-                        if (haveSomethingToCopyToDrmProvider(msgItem.mMsgId)) {
-                            menu.add(0, MENU_COPY_TO_DRM_PROVIDER, 0,
+                        if (isDrmRingtoneWithRights(msgItem.mMsgId)) {
+                            menu.add(0, MENU_SAVE_RINGTONE, 0,
                                     getDrmMimeMenuStringRsrc(msgItem.mMsgId))
                             .setOnMenuItemClickListener(l);
                         }
@@ -1072,8 +1075,7 @@
                 subject += msgItem.mSubject;
             }
             sendReq.setSubject(new EncodedStringValue(subject));
-            sendReq.setBody(msgItem.mSlideshow.makeCopy(
-                    ComposeMessageActivity.this));
+            sendReq.setBody(msgItem.mSlideshow.makeCopy());
 
             Uri uri = null;
             try {
@@ -1166,9 +1168,9 @@
                     return true;
                 }
 
-                case MENU_COPY_TO_DRM_PROVIDER: {
+                case MENU_SAVE_RINGTONE: {
                     int resId = getDrmMimeSavedStringRsrc(mMsgItem.mMsgId,
-                            copyToDrmProvider(mMsgItem.mMsgId));
+                            saveRingtone(mMsgItem.mMsgId));
                     Toast.makeText(ComposeMessageActivity.this, resId, Toast.LENGTH_SHORT).show();
                     return true;
                 }
@@ -1237,7 +1239,7 @@
             }
 
             if (ContentType.isImageType(type) || ContentType.isVideoType(type) ||
-                    ContentType.isAudioType(type)) {
+                    ContentType.isAudioType(type) || DrmUtils.isDrmType(type)) {
                 result = true;
                 break;
             }
@@ -1246,20 +1248,10 @@
     }
 
     /**
-     * Looks to see if there are any drm'd parts of the attachment that can be copied to the
-     * DrmProvider. Right now we only support saving audio (e.g. ringtones).
-     * @param msgId
-     */
-    private boolean haveSomethingToCopyToDrmProvider(long msgId) {
-        String mimeType = getDrmMimeType(msgId);
-        return isAudioMimeType(mimeType);
-    }
-
-    /**
      * Copies media from an Mms to the DrmProvider
      * @param msgId
      */
-    private boolean copyToDrmProvider(long msgId) {
+    private boolean saveRingtone(long msgId) {
         boolean result = true;
         PduBody body = null;
         try {
@@ -1277,51 +1269,55 @@
             PduPart part = body.getPart(i);
             String type = new String(part.getContentType());
 
-            if (ContentType.isDrmType(type)) {
+            if (DrmUtils.isDrmType(type)) {
                 // All parts (but there's probably only a single one) have to be successful
                 // for a valid result.
-                result &= copyPartToDrmProvider(part);
+                result &= copyPart(part, Long.toHexString(msgId));
             }
         }
         return result;
     }
 
-    private String mimeTypeOfDrmPart(PduPart part) {
-        Uri uri = part.getDataUri();
-        InputStream input = null;
+    /**
+     * Returns true if any part is drm'd audio with ringtone rights.
+     * @param msgId
+     * @return true if one of the parts is drm'd audio with rights to save as a ringtone.
+     */
+    private boolean isDrmRingtoneWithRights(long msgId) {
+        PduBody body = null;
         try {
-            input = mContentResolver.openInputStream(uri);
-            if (input instanceof FileInputStream) {
-                FileInputStream fin = (FileInputStream) input;
+            body = SlideshowModel.getPduBody(this,
+                        ContentUris.withAppendedId(Mms.CONTENT_URI, msgId));
+        } catch (MmsException e) {
+            Log.e(TAG, "isDrmRingtoneWithRights can't load pdu body: " + msgId);
+        }
+        if (body == null) {
+            return false;
+        }
 
-                DrmRawContent content = new DrmRawContent(fin, fin.available(),
-                        DrmRawContent.DRM_MIMETYPE_MESSAGE_STRING);
-                String mimeType = content.getContentType();
-                return mimeType;
-            }
-        } catch (IOException e) {
-            // Ignore
-            Log.e(TAG, "IOException caught while opening or reading stream", e);
-        } catch (DrmException e) {
-            Log.e(TAG, "DrmException caught ", e);
-        } finally {
-            if (null != input) {
-                try {
-                    input.close();
-                } catch (IOException e) {
-                    // Ignore
-                    Log.e(TAG, "IOException caught while closing stream", e);
+        int partNum = body.getPartsNum();
+        for (int i = 0; i < partNum; i++) {
+            PduPart part = body.getPart(i);
+            String type = new String(part.getContentType());
+
+            if (DrmUtils.isDrmType(type)) {
+                String mimeType = MmsApp.getApplication().getDrmManagerClient()
+                        .getOriginalMimeType(part.getDataUri());
+                if (ContentType.isAudioType(mimeType) && DrmUtils.haveRightsForAction(part.getDataUri(),
+                        DrmStore.Action.RINGTONE)) {
+                    return true;
                 }
             }
         }
-        return null;
+        return false;
     }
 
     /**
-     * Returns the type of the first drm'd pdu part.
+     * Returns true if all drm'd parts are forwardable.
      * @param msgId
+     * @return true if all drm'd parts are forwardable.
      */
-    private String getDrmMimeType(long msgId) {
+    private boolean isForwardable(long msgId) {
         PduBody body = null;
         try {
             body = SlideshowModel.getPduBody(this,
@@ -1330,100 +1326,39 @@
             Log.e(TAG, "getDrmMimeType can't load pdu body: " + msgId);
         }
         if (body == null) {
-            return null;
+            return false;
         }
 
         int partNum = body.getPartsNum();
-        for(int i = 0; i < partNum; i++) {
+        for (int i = 0; i < partNum; i++) {
             PduPart part = body.getPart(i);
             String type = new String(part.getContentType());
 
-            if (ContentType.isDrmType(type)) {
-                return mimeTypeOfDrmPart(part);
+            if (DrmUtils.isDrmType(type) && !DrmUtils.haveRightsForAction(part.getDataUri(),
+                        DrmStore.Action.TRANSFER)) {
+                    return false;
             }
         }
-        return null;
+        return true;
     }
 
     private int getDrmMimeMenuStringRsrc(long msgId) {
-        String mimeType = getDrmMimeType(msgId);
-        if (isAudioMimeType(mimeType)) {
+        if (isDrmRingtoneWithRights(msgId)) {
             return R.string.save_ringtone;
         }
         return 0;
     }
 
     private int getDrmMimeSavedStringRsrc(long msgId, boolean success) {
-        String mimeType = getDrmMimeType(msgId);
-        if (isAudioMimeType(mimeType)) {
+        if (isDrmRingtoneWithRights(msgId)) {
             return success ? R.string.saved_ringtone : R.string.saved_ringtone_fail;
         }
         return 0;
     }
 
-    private boolean isAudioMimeType(String mimeType) {
-        return mimeType != null && mimeType.startsWith("audio/");
-    }
-
-    private boolean isImageMimeType(String mimeType) {
-        return mimeType != null && mimeType.startsWith("image/");
-    }
-
-    private boolean copyPartToDrmProvider(PduPart part) {
-        Uri uri = part.getDataUri();
-
-        InputStream input = null;
-        try {
-            input = mContentResolver.openInputStream(uri);
-            if (input instanceof FileInputStream) {
-                FileInputStream fin = (FileInputStream) input;
-
-                // Build a nice title
-                byte[] location = part.getName();
-                if (location == null) {
-                    location = part.getFilename();
-                }
-                if (location == null) {
-                    location = part.getContentLocation();
-                }
-
-                // Depending on the location, there may be an
-                // extension already on the name or not
-                String title = new String(location);
-                int index;
-                if ((index = title.indexOf(".")) == -1) {
-                    String type = new String(part.getContentType());
-                } else {
-                    title = title.substring(0, index);
-                }
-
-                // transfer the file to the DRM content provider
-                Intent item = DrmStore.addDrmFile(mContentResolver, fin, title);
-                if (item == null) {
-                    Log.w(TAG, "unable to add file " + uri + " to DrmProvider");
-                    return false;
-                }
-            }
-        } catch (IOException e) {
-            // Ignore
-            Log.e(TAG, "IOException caught while opening or reading stream", e);
-            return false;
-        } finally {
-            if (null != input) {
-                try {
-                    input.close();
-                } catch (IOException e) {
-                    // Ignore
-                    Log.e(TAG, "IOException caught while closing stream", e);
-                    return false;
-                }
-            }
-        }
-        return true;
-    }
-
     /**
-     * Copies media from an Mms to the "download" directory on the SD card
+     * Copies media from an Mms to the "download" directory on the SD card. If any of the parts
+     * are audio types, drm'd or not, they're copied to the "Ringtones" directory.
      * @param msgId
      */
     private boolean copyMedia(long msgId) {
@@ -1442,19 +1377,25 @@
         int partNum = body.getPartsNum();
         for(int i = 0; i < partNum; i++) {
             PduPart part = body.getPart(i);
-            String type = new String(part.getContentType());
 
-            if (ContentType.isImageType(type) || ContentType.isVideoType(type) ||
-                    ContentType.isAudioType(type)) {
-                result &= copyPart(part, Long.toHexString(msgId));   // all parts have to be successful for a valid result.
-            }
+            // all parts have to be successful for a valid result.
+            result &= copyPart(part, Long.toHexString(msgId));
         }
         return result;
     }
 
     private boolean copyPart(PduPart part, String fallback) {
         Uri uri = part.getDataUri();
-
+        String type = new String(part.getContentType());
+        boolean isDrm = DrmUtils.isDrmType(type);
+        if (isDrm) {
+            type = MmsApp.getApplication().getDrmManagerClient()
+                    .getOriginalMimeType(part.getDataUri());
+        }
+        if (ContentType.APP_SMIL.equals(type)) {
+            return true;    // we're not going to save the "application/smil" that often can
+                            // be a downloaded part. Pretend it was saved.
+        }
         InputStream input = null;
         FileOutputStream fout = null;
         try {
@@ -1484,19 +1425,22 @@
                                                     // stored down to just the leaf filename.
 
                 // Depending on the location, there may be an
-                // extension already on the name or not
+                // extension already on the name or not. If we've got audio, put the attachment
+                // in the Ringtones directory.
                 String dir = Environment.getExternalStorageDirectory() + "/"
-                                + Environment.DIRECTORY_DOWNLOADS  + "/";
+                                + (ContentType.isAudioType(type) ? Environment.DIRECTORY_RINGTONES :
+                                    Environment.DIRECTORY_DOWNLOADS)  + "/";
                 String extension;
                 int index;
                 if ((index = fileName.lastIndexOf('.')) == -1) {
-                    String type = new String(part.getContentType());
                     extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(type);
                 } else {
                     extension = fileName.substring(index + 1, fileName.length());
                     fileName = fileName.substring(0, index);
                 }
-
+                if (isDrm) {
+                    extension += DrmUtils.getConvertExtension(type);
+                }
                 File file = getUniqueDestination(dir + fileName, extension);
 
                 // make sure the path is valid and directories created for this file.
diff --git a/src/com/android/mms/ui/MessageItem.java b/src/com/android/mms/ui/MessageItem.java
index 30707ae..71650ec 100644
--- a/src/com/android/mms/ui/MessageItem.java
+++ b/src/com/android/mms/ui/MessageItem.java
@@ -325,11 +325,7 @@
                 SlideModel slide = mSlideshow == null ? null : mSlideshow.get(0);
                 if ((slide != null) && slide.hasText()) {
                     TextModel tm = slide.getText();
-                    if (tm.isDrmProtected()) {
-                        mBody = mContext.getString(R.string.drm_protected_text);
-                    } else {
-                        mBody = tm.getText();
-                    }
+                    mBody = tm.getText();
                     mTextContentType = tm.getContentType();
                 }
 
diff --git a/src/com/android/mms/ui/MessageUtils.java b/src/com/android/mms/ui/MessageUtils.java
index a15d239..63c36eb 100644
--- a/src/com/android/mms/ui/MessageUtils.java
+++ b/src/com/android/mms/ui/MessageUtils.java
@@ -529,11 +529,7 @@
         intent.putExtra("SingleItemOnly", true); // So we don't see "surrounding" images in Gallery
 
         String contentType;
-        if (mm.isDrmProtected()) {
-            contentType = mm.getDrmObject().getContentType();
-        } else {
-            contentType = mm.getContentType();
-        }
+        contentType = mm.getContentType();
         intent.setDataAndType(mm.getUri(), contentType);
         context.startActivity(intent);
     }
diff --git a/src/com/android/mms/ui/MmsThumbnailPresenter.java b/src/com/android/mms/ui/MmsThumbnailPresenter.java
index 02d18a6..b781001 100644
--- a/src/com/android/mms/ui/MmsThumbnailPresenter.java
+++ b/src/com/android/mms/ui/MmsThumbnailPresenter.java
@@ -85,27 +85,15 @@
     };
 
     private void presentVideoThumbnail(SlideViewInterface view, VideoModel video) {
-        if (video.isDrmProtected()) {
-            showDrmIcon(view, video.getSrc());
-        } else {
-            video.loadThumbnailBitmap(mImageLoadedCallback);
-        }
+        video.loadThumbnailBitmap(mImageLoadedCallback);
     }
 
     private void presentImageThumbnail(SlideViewInterface view, ImageModel image) {
-        if (image.isDrmProtected()) {
-            showDrmIcon(view, image.getSrc());
-        } else {
-            image.loadThumbnailBitmap(mImageLoadedCallback);
-        }
+        image.loadThumbnailBitmap(mImageLoadedCallback);
     }
 
     protected void presentAudioThumbnail(SlideViewInterface view, AudioModel audio) {
-        if (audio.isDrmProtected()) {
-            showDrmIcon(view, audio.getSrc());
-        } else {
-            view.setAudio(audio.getUri(), audio.getSrc(), audio.getExtras());
-        }
+        view.setAudio(audio.getUri(), audio.getSrc(), audio.getExtras());
     }
 
     // Show an icon instead of real content in the thumbnail.
diff --git a/src/com/android/mms/ui/SlideshowPresenter.java b/src/com/android/mms/ui/SlideshowPresenter.java
index 5b03611..b0a4d56 100644
--- a/src/com/android/mms/ui/SlideshowPresenter.java
+++ b/src/com/android/mms/ui/SlideshowPresenter.java
@@ -126,29 +126,20 @@
     protected void presentSlide(SlideViewInterface view, SlideModel model) {
         view.reset();
 
-        try {
-            for (MediaModel media : model) {
-                if (media instanceof RegionMediaModel) {
-                    presentRegionMedia(view, (RegionMediaModel) media, true);
-                } else if (media.isAudio()) {
-                    presentAudio(view, (AudioModel) media, true);
-                }
+        for (MediaModel media : model) {
+            if (media instanceof RegionMediaModel) {
+                presentRegionMedia(view, (RegionMediaModel) media, true);
+            } else if (media.isAudio()) {
+                presentAudio(view, (AudioModel) media, true);
             }
-        } catch (DrmException e) {
-            Log.e(TAG, e.getMessage(), e);
-            Toast.makeText(mContext,
-                    mContext.getString(R.string.insufficient_drm_rights),
-                    Toast.LENGTH_SHORT).show();
         }
     }
 
     /**
      * @param view
-     * @throws DrmException
      */
     protected void presentRegionMedia(SlideViewInterface view,
-            RegionMediaModel rMedia, boolean dataChanged)
-            throws DrmException {
+            RegionMediaModel rMedia, boolean dataChanged) {
         RegionModel r = (rMedia).getRegion();
         if (rMedia.isText()) {
             presentText(view, (TextModel) rMedia, r, dataChanged);
@@ -160,10 +151,10 @@
     }
 
     protected void presentAudio(SlideViewInterface view, AudioModel audio,
-            boolean dataChanged) throws DrmException {
+            boolean dataChanged) {
         // Set audio only when data changed.
         if (dataChanged) {
-            view.setAudio(audio.getUriWithDrmCheck(), audio.getSrc(), audio.getExtras());
+            view.setAudio(audio.getUri(), audio.getSrc(), audio.getExtras());
         }
 
         MediaAction action = audio.getCurrentAction();
@@ -198,10 +189,9 @@
      * @param view
      * @param image
      * @param r
-     * @throws DrmException
      */
     protected void presentImage(SlideViewInterface view, ImageModel image,
-            RegionModel r, boolean dataChanged) throws DrmException {
+            RegionModel r, boolean dataChanged) {
         int transformedWidth = transformWidth(r.getWidth());
         int transformedHeight = transformWidth(r.getHeight());
 
@@ -213,8 +203,7 @@
         }
 
         if (dataChanged) {
-            view.setImage(image.getSrc(),
-                    image.getBitmapWithDrmCheck(r.getWidth(), r.getHeight()));
+            view.setImage(image.getSrc(), image.getBitmap(r.getWidth(), r.getHeight()));
         }
 
         if (view instanceof AdaptableSlideViewInterface) {
@@ -232,15 +221,14 @@
      * @param view
      * @param video
      * @param r
-     * @throws DrmException
      */
     protected void presentVideo(SlideViewInterface view, VideoModel video,
-            RegionModel r, boolean dataChanged) throws DrmException {
+            RegionModel r, boolean dataChanged) {
         if (dataChanged) {
-            view.setVideo(video.getSrc(), video.getUriWithDrmCheck());
+            view.setVideo(video.getSrc(), video.getUri());
         }
 
-        if (view instanceof AdaptableSlideViewInterface) {
+            if (view instanceof AdaptableSlideViewInterface) {
             ((AdaptableSlideViewInterface) view).setVideoRegion(
                     transformWidth(r.getLeft()),
                     transformHeight(r.getTop()),
@@ -305,27 +293,13 @@
             if (model instanceof RegionMediaModel) {
                 mHandler.post(new Runnable() {
                     public void run() {
-                        try {
-                            presentRegionMedia(view, (RegionMediaModel) model, dataChanged);
-                        } catch (DrmException e) {
-                            Log.e(TAG, e.getMessage(), e);
-                            Toast.makeText(mContext,
-                                    mContext.getString(R.string.insufficient_drm_rights),
-                                    Toast.LENGTH_SHORT).show();
-                        }
+                        presentRegionMedia(view, (RegionMediaModel) model, dataChanged);
                     }
                 });
             } else if (((MediaModel) model).isAudio()) {
                 mHandler.post(new Runnable() {
                     public void run() {
-                        try {
-                            presentAudio(view, (AudioModel) model, dataChanged);
-                        } catch (DrmException e) {
-                            Log.e(TAG, e.getMessage(), e);
-                            Toast.makeText(mContext,
-                                    mContext.getString(R.string.insufficient_drm_rights),
-                                    Toast.LENGTH_SHORT).show();
-                        }
+                        presentAudio(view, (AudioModel) model, dataChanged);
                     }
                 });
             }
diff --git a/src/com/android/mms/util/PduLoaderManager.java b/src/com/android/mms/util/PduLoaderManager.java
index 16d9c8f..42b26a5 100644
--- a/src/com/android/mms/util/PduLoaderManager.java
+++ b/src/com/android/mms/util/PduLoaderManager.java
@@ -53,6 +53,7 @@
 public class PduLoaderManager extends BackgroundLoaderManager {
     private static final String TAG = "Mms:PduLoaderManager";
 
+    private static final boolean DEBUG_DISABLE_CACHE = false;
     private static final boolean DEBUG_DISABLE_PDUS = false;
     private static final boolean DEBUG_LONG_WAIT = false;
 
@@ -82,7 +83,8 @@
                 cacheEntry = mPduCache.get(uri);
             }
         }
-        final SlideshowModel slideshow = requestSlideshow ? mSlideshowCache.get(uri) : null;
+        final SlideshowModel slideshow = (requestSlideshow && !DEBUG_DISABLE_CACHE) ?
+                mSlideshowCache.get(uri) : null;
 
         final boolean slideshowExists = (!requestSlideshow || slideshow != null);
         final boolean pduExists = (cacheEntry != null && cacheEntry.getPdu() != null);