summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorGloria Wang <gwang@google.com>2011-06-03 14:36:27 -0700
committerAndroid (Google) Code Review <android-gerrit@google.com>2011-06-03 14:36:27 -0700
commit9356a4a9b1b1e5be9a3bd639cd89bb30aa6a5ae5 (patch)
treeca73fdc56dc900decb29980d03cb4f8778e3e8eb /src
parent9321f8656228b57f42549536512de684ce584a4d (diff)
parent0a17c2a28738d6ecb274def0e8e54f556d89f5f3 (diff)
downloadandroid_packages_providers_DownloadProvider-9356a4a9b1b1e5be9a3bd639cd89bb30aa6a5ae5.tar.gz
android_packages_providers_DownloadProvider-9356a4a9b1b1e5be9a3bd639cd89bb30aa6a5ae5.tar.bz2
android_packages_providers_DownloadProvider-9356a4a9b1b1e5be9a3bd639cd89bb30aa6a5ae5.zip
Merge "Download provider change for DRM Forward Lock plugin: to convert .dm files to .fl files during downloading For bug 3188041"
Diffstat (limited to 'src')
-rw-r--r--src/com/android/providers/downloads/Constants.java4
-rw-r--r--src/com/android/providers/downloads/DownloadDrmHelper.java110
-rw-r--r--src/com/android/providers/downloads/DownloadInfo.java4
-rw-r--r--src/com/android/providers/downloads/DownloadReceiver.java1
-rw-r--r--src/com/android/providers/downloads/DownloadThread.java69
-rw-r--r--src/com/android/providers/downloads/DrmConvertSession.java171
-rw-r--r--src/com/android/providers/downloads/Helpers.java9
-rw-r--r--src/com/android/providers/downloads/StorageManager.java6
8 files changed, 319 insertions, 55 deletions
diff --git a/src/com/android/providers/downloads/Constants.java b/src/com/android/providers/downloads/Constants.java
index ef0c6dbb..977f00b9 100644
--- a/src/com/android/providers/downloads/Constants.java
+++ b/src/com/android/providers/downloads/Constants.java
@@ -91,10 +91,6 @@ public class Constants {
/** The default user agent used for downloads */
public static final String DEFAULT_USER_AGENT = "AndroidDownloadManager";
- /** The MIME type of special DRM files */
- public static final String MIMETYPE_DRM_MESSAGE =
- android.drm.mobile1.DrmRawContent.DRM_MIMETYPE_MESSAGE_STRING;
-
/** The MIME type of APKs */
public static final String MIMETYPE_APK = "application/vnd.android.package";
diff --git a/src/com/android/providers/downloads/DownloadDrmHelper.java b/src/com/android/providers/downloads/DownloadDrmHelper.java
new file mode 100644
index 00000000..10cb792c
--- /dev/null
+++ b/src/com/android/providers/downloads/DownloadDrmHelper.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2011 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.providers.downloads;
+
+import android.content.Context;
+import android.drm.DrmManagerClient;
+import android.util.Log;
+
+public class DownloadDrmHelper {
+
+ /** The MIME type of special DRM files */
+ public static final String MIMETYPE_DRM_MESSAGE = "application/vnd.oma.drm.message";
+
+ /** The extensions of special DRM files */
+ public static final String EXTENSION_DRM_MESSAGE = ".dm";
+
+ public static final String EXTENSION_INTERNAL_FWDL = ".fl";
+
+ /**
+ * Checks if the Media Type is a DRM Media Type
+ *
+ * @param drmManagerClient A DrmManagerClient
+ * @param mimetype Media Type to check
+ * @return True if the Media Type is DRM else false
+ */
+ public static boolean isDrmMimeType(Context context, String mimetype) {
+ boolean result = false;
+ if (context != null) {
+ try {
+ DrmManagerClient drmClient = new DrmManagerClient(context);
+ if (drmClient != null && mimetype != null && mimetype.length() > 0) {
+ result = drmClient.canHandle("", mimetype);
+ }
+ } catch (IllegalArgumentException e) {
+ Log.w(Constants.TAG,
+ "DrmManagerClient instance could not be created, context is Illegal.");
+ } catch (IllegalStateException e) {
+ Log.w(Constants.TAG, "DrmManagerClient didn't initialize properly.");
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Checks if the Media Type needs to be DRM converted
+ *
+ * @param mimetype Media type of the content
+ * @return True if convert is needed else false
+ */
+ public static boolean isDrmConvertNeeded(String mimetype) {
+ return MIMETYPE_DRM_MESSAGE.equals(mimetype);
+ }
+
+ /**
+ * Modifies the file extension for a DRM Forward Lock file NOTE: This
+ * function shouldn't be called if the file shouldn't be DRM converted
+ */
+ public static String modifyDrmFwLockFileExtension(String filename) {
+ if (filename != null) {
+ int extensionIndex;
+ extensionIndex = filename.lastIndexOf(".");
+ if (extensionIndex != -1) {
+ filename = filename.substring(0, extensionIndex);
+ }
+ filename = filename.concat(EXTENSION_INTERNAL_FWDL);
+ }
+ return filename;
+ }
+
+ /**
+ * Gets the original mime type of DRM protected content.
+ *
+ * @param context The context
+ * @param path Path to the file
+ * @param containingMime The current mime type of of the file i.e. the
+ * containing mime type
+ * @return The original mime type of the file if DRM protected else the
+ * currentMime
+ */
+ public static String getOriginalMimeType(Context context, String path, String containingMime) {
+ String result = containingMime;
+ DrmManagerClient drmClient = new DrmManagerClient(context);
+ try {
+ if (drmClient.canHandle(path, null)) {
+ result = drmClient.getOriginalMimeType(path);
+ }
+ } catch (IllegalArgumentException ex) {
+ Log.w(Constants.TAG,
+ "Can't get original mime type since path is null or empty string.");
+ } catch (IllegalStateException ex) {
+ Log.w(Constants.TAG, "DrmManagerClient didn't initialize properly.");
+ }
+ return result;
+ }
+}
diff --git a/src/com/android/providers/downloads/DownloadInfo.java b/src/com/android/providers/downloads/DownloadInfo.java
index fe6613f7..313386fe 100644
--- a/src/com/android/providers/downloads/DownloadInfo.java
+++ b/src/com/android/providers/downloads/DownloadInfo.java
@@ -23,7 +23,6 @@ import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
-import android.drm.mobile1.DrmRawContent;
import android.net.ConnectivityManager;
import android.net.Uri;
import android.os.Environment;
@@ -521,8 +520,7 @@ public class DownloadInfo {
&& (mDestination == Downloads.Impl.DESTINATION_EXTERNAL ||
mDestination == Downloads.Impl.DESTINATION_FILE_URI ||
mDestination == Downloads.Impl.DESTINATION_NON_DOWNLOADMANAGER_DOWNLOAD)
- && Downloads.Impl.isStatusSuccess(mStatus)
- && !DrmRawContent.DRM_MIMETYPE_MESSAGE_STRING.equalsIgnoreCase(mMimeType);
+ && Downloads.Impl.isStatusSuccess(mStatus);
}
void notifyPauseDueToSize(boolean isWifiRequired) {
diff --git a/src/com/android/providers/downloads/DownloadReceiver.java b/src/com/android/providers/downloads/DownloadReceiver.java
index 7372e4ac..b01384bb 100644
--- a/src/com/android/providers/downloads/DownloadReceiver.java
+++ b/src/com/android/providers/downloads/DownloadReceiver.java
@@ -150,6 +150,7 @@ public class DownloadReceiver extends BroadcastReceiver {
}
Intent activityIntent = new Intent(Intent.ACTION_VIEW);
+ mimetype = DownloadDrmHelper.getOriginalMimeType(context, filename, mimetype);
activityIntent.setDataAndType(path, mimetype);
activityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
diff --git a/src/com/android/providers/downloads/DownloadThread.java b/src/com/android/providers/downloads/DownloadThread.java
index 082caa22..7ddfe959 100644
--- a/src/com/android/providers/downloads/DownloadThread.java
+++ b/src/com/android/providers/downloads/DownloadThread.java
@@ -21,7 +21,6 @@ import org.apache.http.conn.params.ConnRouteParams;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
-import android.drm.mobile1.DrmRawContent;
import android.net.http.AndroidHttpClient;
import android.net.Proxy;
import android.net.TrafficStats;
@@ -29,7 +28,6 @@ import android.os.FileUtils;
import android.os.PowerManager;
import android.os.Process;
import android.provider.Downloads;
-import android.provider.DrmStore;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
@@ -57,6 +55,7 @@ public class DownloadThread extends Thread {
private final DownloadInfo mInfo;
private final SystemFacade mSystemFacade;
private final StorageManager mStorageManager;
+ private DrmConvertSession mDrmConvertSession;
public DownloadThread(Context context, SystemFacade systemFacade, DownloadInfo info,
StorageManager storageManager) {
@@ -290,13 +289,9 @@ public class DownloadThread extends Thread {
* Called after a successful completion to take any necessary action on the downloaded file.
*/
private void finalizeDestinationFile(State state) throws StopRequestException {
- if (isDrmFile(state)) {
- transferToDrm(state);
- } else {
- // make sure the file is readable
- FileUtils.setPermissions(state.mFilename, 0644, -1, -1);
- syncDestination(state);
- }
+ // make sure the file is readable
+ FileUtils.setPermissions(state.mFilename, 0644, -1, -1);
+ syncDestination(state);
}
/**
@@ -304,6 +299,10 @@ public class DownloadThread extends Thread {
* the downloaded file.
*/
private void cleanupDestination(State state, int finalStatus) {
+ if (mDrmConvertSession != null) {
+ finalStatus = mDrmConvertSession.close(state.mFilename);
+ }
+
closeDestination(state);
if (state.mFilename != null && Downloads.Impl.isStatusError(finalStatus)) {
new File(state.mFilename).delete();
@@ -341,30 +340,6 @@ public class DownloadThread extends Thread {
}
/**
- * @return true if the current download is a DRM file
- */
- private boolean isDrmFile(State state) {
- return DrmRawContent.DRM_MIMETYPE_MESSAGE_STRING.equalsIgnoreCase(state.mMimeType);
- }
-
- /**
- * Transfer the downloaded destination file to the DRM store.
- */
- private void transferToDrm(State state) throws StopRequestException {
- File file = new File(state.mFilename);
- Intent item = DrmStore.addDrmFile(mContext.getContentResolver(), file, null);
- file.delete();
-
- if (item == null) {
- throw new StopRequestException(Downloads.Impl.STATUS_UNKNOWN_ERROR,
- "unable to add file to DrmProvider");
- } else {
- state.mFilename = item.getDataString();
- state.mMimeType = item.getType();
- }
- }
-
- /**
* Close the destination output stream.
*/
private void closeDestination(State state) {
@@ -429,10 +404,16 @@ public class DownloadThread extends Thread {
}
mStorageManager.verifySpaceBeforeWritingToFile(mInfo.mDestination, state.mFilename,
bytesRead);
- state.mStream.write(data, 0, bytesRead);
- if (mInfo.mDestination == Downloads.Impl.DESTINATION_EXTERNAL
- && !isDrmFile(state)) {
- closeDestination(state);
+ if (!DownloadDrmHelper.isDrmConvertNeeded(mInfo.mMimeType)) {
+ state.mStream.write(data, 0, bytesRead);
+ } else {
+ byte[] convertedData = mDrmConvertSession.convert(data, bytesRead);
+ if (convertedData != null) {
+ state.mStream.write(convertedData, 0, convertedData.length);
+ } else {
+ throw new StopRequestException(Downloads.Impl.STATUS_FILE_ERROR,
+ "Error converting drm data.");
+ }
}
return;
} catch (IOException ex) {
@@ -442,6 +423,10 @@ public class DownloadThread extends Thread {
if (state.mStream != null) {
mStorageManager.verifySpace(mInfo.mDestination, state.mFilename, bytesRead);
}
+ } finally {
+ if (mInfo.mDestination == Downloads.Impl.DESTINATION_EXTERNAL) {
+ closeDestination(state);
+ }
}
}
}
@@ -536,6 +521,13 @@ public class DownloadThread extends Thread {
}
readResponseHeaders(state, innerState, response);
+ if (DownloadDrmHelper.isDrmConvertNeeded(state.mMimeType)) {
+ mDrmConvertSession = DrmConvertSession.open(mContext, state.mMimeType);
+ if (mDrmConvertSession == null) {
+ throw new StopRequestException(Downloads.Impl.STATUS_NOT_ACCEPTABLE, "Mimetype "
+ + state.mMimeType + " can not be converted.");
+ }
+ }
state.mFilename = Helpers.generateSaveFile(
mContext,
@@ -861,8 +853,7 @@ public class DownloadThread extends Thread {
}
}
- if (state.mStream != null && mInfo.mDestination == Downloads.Impl.DESTINATION_EXTERNAL
- && !isDrmFile(state)) {
+ if (state.mStream != null && mInfo.mDestination == Downloads.Impl.DESTINATION_EXTERNAL) {
closeDestination(state);
}
}
diff --git a/src/com/android/providers/downloads/DrmConvertSession.java b/src/com/android/providers/downloads/DrmConvertSession.java
new file mode 100644
index 00000000..d10edf14
--- /dev/null
+++ b/src/com/android/providers/downloads/DrmConvertSession.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2011 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.providers.downloads;
+
+import android.content.Context;
+import android.drm.DrmConvertedStatus;
+import android.drm.DrmManagerClient;
+import android.util.Log;
+import android.provider.Downloads;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+
+public class DrmConvertSession {
+ private DrmManagerClient mDrmClient;
+ private int mConvertSessionId;
+
+ private DrmConvertSession(DrmManagerClient drmClient, int convertSessionId) {
+ mDrmClient = drmClient;
+ mConvertSessionId = convertSessionId;
+ }
+
+ /**
+ * Start of converting a file.
+ *
+ * @param context The context of the application running the convert session.
+ * @param mimeType Mimetype of content that shall be converted.
+ * @return A convert session or null in case an error occurs.
+ */
+ public static DrmConvertSession open(Context context, String mimeType) {
+ DrmManagerClient drmClient = null;
+ int convertSessionId = -1;
+ if (context != null && mimeType != null && !mimeType.equals("")) {
+ try {
+ drmClient = new DrmManagerClient(context);
+ try {
+ convertSessionId = drmClient.openConvertSession(mimeType);
+ } catch (IllegalArgumentException e) {
+ Log.w(Constants.TAG, "Conversion of Mimetype: " + mimeType
+ + " is not supported.", e);
+ } catch (IllegalStateException e) {
+ Log.w(Constants.TAG, "Could not access Open DrmFramework.", e);
+ }
+ } catch (IllegalArgumentException e) {
+ Log.w(Constants.TAG,
+ "DrmManagerClient instance could not be created, context is Illegal.");
+ } catch (IllegalStateException e) {
+ Log.w(Constants.TAG, "DrmManagerClient didn't initialize properly.");
+ }
+ }
+
+ if (drmClient == null || convertSessionId < 0) {
+ return null;
+ } else {
+ return new DrmConvertSession(drmClient, convertSessionId);
+ }
+ }
+ /**
+ * Convert a buffer of data to protected format.
+ *
+ * @param buffer Buffer filled with data to convert.
+ * @param size The number of bytes that shall be converted.
+ * @return A Buffer filled with converted data, if execution is ok, in all
+ * other case null.
+ */
+ public byte [] convert(byte[] inBuffer, int size) {
+ byte[] result = null;
+ if (inBuffer != null) {
+ DrmConvertedStatus convertedStatus = null;
+ try {
+ if (size != inBuffer.length) {
+ byte[] buf = new byte[size];
+ System.arraycopy(inBuffer, 0, buf, 0, size);
+ convertedStatus = mDrmClient.convertData(mConvertSessionId, buf);
+ } else {
+ convertedStatus = mDrmClient.convertData(mConvertSessionId, inBuffer);
+ }
+
+ if (convertedStatus != null &&
+ convertedStatus.statusCode == DrmConvertedStatus.STATUS_OK &&
+ convertedStatus.convertedData != null) {
+ result = convertedStatus.convertedData;
+ }
+ } catch (IllegalArgumentException e) {
+ Log.w(Constants.TAG, "Buffer with data to convert is illegal. Convertsession: "
+ + mConvertSessionId, e);
+ } catch (IllegalStateException e) {
+ Log.w(Constants.TAG, "Could not convert data. Convertsession: " +
+ mConvertSessionId, e);
+ }
+ } else {
+ throw new IllegalArgumentException("Parameter inBuffer is null");
+ }
+ return result;
+ }
+
+ /**
+ * Ends a conversion session of a file.
+ *
+ * @param fileName The filename of the converted file.
+ * @return Downloads.Impl.STATUS_SUCCESS if execution is ok.
+ * Downloads.Impl.STATUS_FILE_ERROR in case converted file can not
+ * be accessed. Downloads.Impl.STATUS_NOT_ACCEPTABLE if a problem
+ * occurs when accessing drm framework.
+ * Downloads.Impl.STATUS_UNKNOWN_ERROR if a general error occurred.
+ */
+ public int close(String filename) {
+ DrmConvertedStatus convertedStatus = null;
+ int result = Downloads.Impl.STATUS_UNKNOWN_ERROR;
+ if (mDrmClient != null && mConvertSessionId >= 0) {
+ try {
+ convertedStatus = mDrmClient.closeConvertSession(mConvertSessionId);
+ if (convertedStatus == null ||
+ convertedStatus.statusCode != DrmConvertedStatus.STATUS_OK ||
+ convertedStatus.convertedData == null) {
+ result = Downloads.Impl.STATUS_NOT_ACCEPTABLE;
+ } else {
+ RandomAccessFile rndAccessFile = null;
+ try {
+ rndAccessFile = new RandomAccessFile(filename, "rw");
+ rndAccessFile.seek(convertedStatus.offset);
+ rndAccessFile.write(convertedStatus.convertedData);
+ result = Downloads.Impl.STATUS_SUCCESS;
+ } catch (FileNotFoundException e) {
+ result = Downloads.Impl.STATUS_FILE_ERROR;
+ Log.w(Constants.TAG, "File: " + filename + " could not be found.", e);
+ } catch (IOException e) {
+ result = Downloads.Impl.STATUS_FILE_ERROR;
+ Log.w(Constants.TAG, "Could not access File: " + filename + " .", e);
+ } catch (IllegalArgumentException e) {
+ result = Downloads.Impl.STATUS_FILE_ERROR;
+ Log.w(Constants.TAG, "Could not open file in mode: rw", e);
+ } catch (SecurityException e) {
+ Log.w(Constants.TAG, "Access to File: " + filename +
+ " was denied denied by SecurityManager.", e);
+ } finally {
+ if (rndAccessFile != null) {
+ try {
+ rndAccessFile.close();
+ } catch (IOException e) {
+ result = Downloads.Impl.STATUS_FILE_ERROR;
+ Log.w(Constants.TAG, "Failed to close File:" + filename
+ + ".", e);
+ }
+ }
+ }
+ }
+ } catch (IllegalStateException e) {
+ Log.w(Constants.TAG, "Could not close convertsession. Convertsession: " +
+ mConvertSessionId, e);
+ }
+ }
+ return result;
+ }
+}
diff --git a/src/com/android/providers/downloads/Helpers.java b/src/com/android/providers/downloads/Helpers.java
index 1ac77d51..543b652d 100644
--- a/src/com/android/providers/downloads/Helpers.java
+++ b/src/com/android/providers/downloads/Helpers.java
@@ -20,7 +20,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-import android.drm.mobile1.DrmRawContent;
import android.net.Uri;
import android.os.Environment;
import android.os.SystemClock;
@@ -90,7 +89,11 @@ public class Helpers {
destination);
}
storageManager.verifySpace(destination, path, contentLength);
- return getFullPath(path, mimeType, destination, base);
+ path = getFullPath(path, mimeType, destination, base);
+ if (DownloadDrmHelper.isDrmConvertNeeded(mimeType)) {
+ path = DownloadDrmHelper.modifyDrmFwLockFileExtension(path);
+ }
+ return path;
}
static String getFullPath(String filename, String mimeType, int destination,
@@ -131,7 +134,7 @@ public class Helpers {
throw new StopRequestException(Downloads.Impl.STATUS_NOT_ACCEPTABLE,
"external download with no mime type not allowed");
}
- if (!DrmRawContent.DRM_MIMETYPE_MESSAGE_STRING.equalsIgnoreCase(mimeType)) {
+ if (!DownloadDrmHelper.isDrmMimeType(context, mimeType)) {
// Check to see if we are allowed to download this file. Only files
// that can be handled by the platform can be downloaded.
// special case DRM files, which we should always allow downloading.
diff --git a/src/com/android/providers/downloads/StorageManager.java b/src/com/android/providers/downloads/StorageManager.java
index ed241794..228f6681 100644
--- a/src/com/android/providers/downloads/StorageManager.java
+++ b/src/com/android/providers/downloads/StorageManager.java
@@ -21,7 +21,6 @@ import android.content.Context;
import android.content.res.Resources;
import android.database.Cursor;
import android.database.sqlite.SQLiteException;
-import android.drm.mobile1.DrmRawContent;
import android.net.Uri;
import android.os.Environment;
import android.os.StatFs;
@@ -293,11 +292,6 @@ class StorageManager {
}
return base;
default:
- // DRM messages should be temporarily stored internally and then passed to
- // the DRM content provider
- if (DrmRawContent.DRM_MIMETYPE_MESSAGE_STRING.equalsIgnoreCase(mimeType)) {
- return mDownloadDataDir;
- }
throw new IllegalStateException("unexpected value for destination: " + destination);
}
}