diff options
author | aimitakeshi <aimitakeshi@gmail.com> | 2010-07-29 10:12:27 +0900 |
---|---|---|
committer | aimitakeshi <aimitakeshi@gmail.com> | 2010-09-01 15:40:00 +0900 |
commit | d074e30ce44b9e33da43b67a4515b8986ca72b26 (patch) | |
tree | cea9a809ad3b678713d10b938eb21f0d792a89d8 /drm/java | |
parent | f470ed8630e9e648727443b065b9f1c69fee34d6 (diff) | |
download | frameworks_base-d074e30ce44b9e33da43b67a4515b8986ca72b26.zip frameworks_base-d074e30ce44b9e33da43b67a4515b8986ca72b26.tar.gz frameworks_base-d074e30ce44b9e33da43b67a4515b8986ca72b26.tar.bz2 |
Initial contribution from Sony Corporation.
Add DRM Framework to support DRM content playback
together with StageFright.
- DRM Framework code is added
- include/drm
- drm
- api/current.xml is updated to include DRM Framework Java APIs
- cmds/servicemanager/service_manager.c is modified
to add drmManager and drmIOService.
Change-Id: I6d7bc9c7067362b500e530988a9ce241761866fb
Diffstat (limited to 'drm/java')
-rw-r--r-- | drm/java/android/drm/DrmConvertedStatus.java | 52 | ||||
-rw-r--r-- | drm/java/android/drm/DrmEvent.java | 72 | ||||
-rw-r--r-- | drm/java/android/drm/DrmInfo.java | 154 | ||||
-rw-r--r-- | drm/java/android/drm/DrmInfoEvent.java | 77 | ||||
-rw-r--r-- | drm/java/android/drm/DrmInfoRequest.java | 147 | ||||
-rw-r--r-- | drm/java/android/drm/DrmInfoStatus.java | 50 | ||||
-rw-r--r-- | drm/java/android/drm/DrmManagerClient.java | 487 | ||||
-rw-r--r-- | drm/java/android/drm/DrmRights.java | 182 | ||||
-rw-r--r-- | drm/java/android/drm/DrmStore.java | 199 | ||||
-rw-r--r-- | drm/java/android/drm/DrmSupportInfo.java | 153 | ||||
-rw-r--r-- | drm/java/android/drm/DrmUtils.java | 188 | ||||
-rw-r--r-- | drm/java/android/drm/ProcessedData.java | 83 |
12 files changed, 1844 insertions, 0 deletions
diff --git a/drm/java/android/drm/DrmConvertedStatus.java b/drm/java/android/drm/DrmConvertedStatus.java new file mode 100644 index 0000000..f200552 --- /dev/null +++ b/drm/java/android/drm/DrmConvertedStatus.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2010 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 android.drm; + +/** + * This is an entity class which wraps the status of the conversion, the converted + * data/checksum data and the offset. Offset is going to be used in the case of close + * session where the agent will inform where the header and body signature should be added + * + * As a result of {@link DrmManagerClient#convertData(int, byte [])} and + * {@link DrmManagerClient#closeConvertSession(int)} an instance of DrmConvertedStatus + * would be returned. + * + */ +public class DrmConvertedStatus { + // Should be in sync with DrmConvertedStatus.cpp + public static final int STATUS_OK = 1; + public static final int STATUS_INPUTDATA_ERROR = 2; + public static final int STATUS_ERROR = 3; + + public final int statusCode; + public final byte[] convertedData; + public final int offset; + + /** + * constructor to create DrmConvertedStatus object with given parameters + * + * @param _statusCode Status of the conversion + * @param _convertedData Converted data/checksum data + * @param _offset Offset value + */ + public DrmConvertedStatus(int _statusCode, byte[] _convertedData, int _offset) { + statusCode = _statusCode; + convertedData = _convertedData; + offset = _offset; + } +} + diff --git a/drm/java/android/drm/DrmEvent.java b/drm/java/android/drm/DrmEvent.java new file mode 100644 index 0000000..44c4b43 --- /dev/null +++ b/drm/java/android/drm/DrmEvent.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2010 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 android.drm; + +/** + * This is the base class which would be used to notify the caller + * about any event occurred in DRM framework. + * + */ +public class DrmEvent { + private final int mUniqueId; + private final int mType; + private String mMessage = ""; + + /** + * constructor for DrmEvent class + * + * @param uniqueId Unique session identifier + * @param type Type of information + * @param message Message description + */ + protected DrmEvent(int uniqueId, int type, String message) { + mUniqueId = uniqueId; + mType = type; + + if (null != message) { + mMessage = message; + } + } + + /** + * Returns the Unique Id associated with this object + * + * @return Unique Id + */ + public int getUniqueId() { + return mUniqueId; + } + + /** + * Returns the Type of information associated with this object + * + * @return Type of information + */ + public int getType() { + return mType; + } + + /** + * Returns the message description associated with this object + * + * @return message description + */ + public String getMessage() { + return mMessage; + } +} + diff --git a/drm/java/android/drm/DrmInfo.java b/drm/java/android/drm/DrmInfo.java new file mode 100644 index 0000000..7d3fbf1 --- /dev/null +++ b/drm/java/android/drm/DrmInfo.java @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2010 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 android.drm; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Iterator; + +/** + * This is an entity class in which necessary information required to transact + * between device and online DRM server is described. DRM Framework achieves + * server registration, license acquisition and any other server related transaction + * by passing an instance of this class to {@link DrmManagerClient#processDrmInfo(DrmInfo)}. + * + * Caller can retrieve the {@link DrmInfo} instance by using + * {@link DrmManagerClient#acquireDrmInfo(DrmInfoRequest)} + * by passing {@link DrmInfoRequest} instance. + * + */ +public class DrmInfo { + private byte[] mData; + private final String mMimeType; + private final int mInfoType; + // It would be used to add attributes specific to + // DRM scheme such as account id, path or multiple path's + private final HashMap<String, Object> mAttributes = new HashMap<String, Object>(); + + /** + * constructor to create DrmInfo object with given parameters + * + * @param infoType Type of information + * @param data Trigger data + * @param mimeType MIME type + */ + public DrmInfo(int infoType, byte[] data, String mimeType) { + mInfoType = infoType; + mMimeType = mimeType; + mData = data; + } + + /** + * constructor to create DrmInfo object with given parameters + * + * @param infoType Type of information + * @param path Trigger data + * @param mimeType MIME type + */ + public DrmInfo(int infoType, String path, String mimeType) { + mInfoType = infoType; + mMimeType = mimeType; + try { + mData = DrmUtils.readBytes(path); + } catch (IOException e) { + // As the given path is invalid, + // set mData = null, so that further processDrmInfo() + // call would fail with IllegalArgumentException because of mData = null + mData = null; + } + } + + /** + * Adds optional information as <key, value> pair to this object + * + * @param key Key to add + * @param value Value to add + * To put custom object into DrmInfo, custom object has to + * override toString() implementation. + */ + public void put(String key, Object value) { + mAttributes.put(key, value); + } + + /** + * Retrieves the value of given key, if not found returns null + * + * @param key Key whose value to be retrieved + * @return The value or null + */ + public Object get(String key) { + return mAttributes.get(key); + } + + /** + * Returns Iterator object to walk through the keys associated with this instance + * + * @return Iterator object + */ + public Iterator<String> keyIterator() { + return mAttributes.keySet().iterator(); + } + + /** + * Returns Iterator object to walk through the values associated with this instance + * + * @return Iterator object + */ + public Iterator<Object> iterator() { + return mAttributes.values().iterator(); + } + + /** + * Returns the trigger data associated with this object + * + * @return Trigger data + */ + public byte[] getData() { + return mData; + } + + /** + * Returns the mimetype associated with this object + * + * @return MIME type + */ + public String getMimeType() { + return mMimeType; + } + + /** + * Returns information type associated with this instance + * + * @return Information type + */ + public int getInfoType() { + return mInfoType; + } + + /** + * Returns whether this instance is valid or not + * + * @return + * true if valid + * false if invalid + */ + boolean isValid() { + return (null != mMimeType && !mMimeType.equals("") + && null != mData && mData.length > 0 && DrmInfoRequest.isValidType(mInfoType)); + } +} + diff --git a/drm/java/android/drm/DrmInfoEvent.java b/drm/java/android/drm/DrmInfoEvent.java new file mode 100644 index 0000000..be1b009 --- /dev/null +++ b/drm/java/android/drm/DrmInfoEvent.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2010 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 android.drm; + +/** + * This is an entity class which would be passed to caller in + * {@link DrmManagerClient.OnInfoListener#onInfo(DrmManagerClient, DrmInfoEvent)} + * + */ +public class DrmInfoEvent extends DrmEvent { + /** + * TYPE_ALREADY_REGISTERED_BY_ANOTHER_ACCOUNT, when registration has been already done + * by another account ID. + */ + public static final int TYPE_ALREADY_REGISTERED_BY_ANOTHER_ACCOUNT = 0x0000001; + /** + * TYPE_REMOVE_RIGHTS, when the rights needs to be removed completely. + */ + public static final int TYPE_REMOVE_RIGHTS = 0x0000002; + /** + * TYPE_RIGHTS_INSTALLED, when the rights are downloaded and installed ok. + */ + public static final int TYPE_RIGHTS_INSTALLED = 0x0000003; + /** + * TYPE_RIGHTS_NOT_INSTALLED, when something went wrong installing the rights. + */ + public static final int TYPE_RIGHTS_NOT_INSTALLED = 0x0000004; + /** + * TYPE_RIGHTS_RENEWAL_NOT_ALLOWED, when the server rejects renewal of rights. + */ + public static final int TYPE_RIGHTS_RENEWAL_NOT_ALLOWED = 0x0000005; + /** + * TYPE_NOT_SUPPORTED, when answer from server can not be handled by the native agent. + */ + public static final int TYPE_NOT_SUPPORTED = 0x0000006; + /** + * TYPE_WAIT_FOR_RIGHTS, rights object is on it's way to phone, + * wait before calling checkRights again. + */ + public static final int TYPE_WAIT_FOR_RIGHTS = 0x0000007; + /** + * TYPE_OUT_OF_MEMORY, when memory allocation fail during renewal. + * Can in the future perhaps be used to trigger garbage collector. + */ + public static final int TYPE_OUT_OF_MEMORY = 0x0000008; + /** + * TYPE_NO_INTERNET_CONNECTION, when the Internet connection is missing and no attempt + * can be made to renew rights. + */ + public static final int TYPE_NO_INTERNET_CONNECTION = 0x0000009; + + /** + * constructor to create DrmInfoEvent object with given parameters + * + * @param uniqueId Unique session identifier + * @param type Type of information + * @param message Message description + */ + public DrmInfoEvent(int uniqueId, int type, String message) { + super(uniqueId, type, message); + } +} + diff --git a/drm/java/android/drm/DrmInfoRequest.java b/drm/java/android/drm/DrmInfoRequest.java new file mode 100644 index 0000000..a5a799c --- /dev/null +++ b/drm/java/android/drm/DrmInfoRequest.java @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2010 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 android.drm; + +import java.util.HashMap; +import java.util.Iterator; + +/** + * This is an entity class used to pass required parameters to get + * the necessary information to communicate with online DRM server + * + * An instance of this class is passed to {@link DrmManagerClient#acquireDrmInfo(DrmInfoRequest)} + * to get the instance of {@link DrmInfo} + * + */ +public class DrmInfoRequest { + // Changes in following constants should be in sync with DrmInfoRequest.cpp + /** + * Constants defines the type of {@link DrmInfoRequest} + */ + public static final int TYPE_REGISTRATION_INFO = 1; + public static final int TYPE_UNREGISTRATION_INFO = 2; + public static final int TYPE_RIGHTS_ACQUISITION_INFO = 3; + public static final int TYPE_RIGHTS_ACQUISITION_PROGRESS_INFO = 4; + + /** + * Key to pass the unique id for the account or the user + */ + public static final String ACCOUNT_ID = "account_id"; + + /** + * Key to pass the unique id used for subscription + */ + public static final String SUBSCRIPTION_ID = "subscription_id"; + + private final int mInfoType; + private final String mMimeType; + private final HashMap<String, Object> mRequestInformation = new HashMap<String, Object>(); + + /** + * constructor to create DrmInfoRequest object with type and mimetype + * + * @param infoType Type of information + * @param mimeType MIME type + */ + public DrmInfoRequest(int infoType, String mimeType) { + mInfoType = infoType; + mMimeType = mimeType; + } + + /** + * Returns the mimetype associated with this object + * + * @return MIME type + */ + public String getMimeType() { + return mMimeType; + } + + /** + * Returns Information type associated with this instance + * + * @return Information type + */ + public int getInfoType() { + return mInfoType; + } + + /** + * Adds optional information as <key, value> pair to this object. + * + * @param key Key to add + * @param value Value to add + */ + public void put(String key, Object value) { + mRequestInformation.put(key, value); + } + + /** + * Retrieves the value of given key, if not found returns null + * + * @param key Key whose value to be retrieved + * @return The value or null + */ + public Object get(String key) { + return mRequestInformation.get(key); + } + + /** + * Returns Iterator object to walk through the keys associated with this instance + * + * @return Iterator object + */ + public Iterator<String> keyIterator() { + return mRequestInformation.keySet().iterator(); + } + + /** + * Returns Iterator object to walk through the values associated with this instance + * + * @return Iterator object + */ + public Iterator<Object> iterator() { + return mRequestInformation.values().iterator(); + } + + /** + * Returns whether this instance is valid or not + * + * @return + * true if valid + * false if invalid + */ + boolean isValid() { + return (null != mMimeType && !mMimeType.equals("") + && null != mRequestInformation && isValidType(mInfoType)); + } + + /* package */ static boolean isValidType(int infoType) { + boolean isValid = false; + + switch (infoType) { + case TYPE_REGISTRATION_INFO: + case TYPE_UNREGISTRATION_INFO: + case TYPE_RIGHTS_ACQUISITION_INFO: + case TYPE_RIGHTS_ACQUISITION_PROGRESS_INFO: + isValid = true; + break; + } + return isValid; + } +} + diff --git a/drm/java/android/drm/DrmInfoStatus.java b/drm/java/android/drm/DrmInfoStatus.java new file mode 100644 index 0000000..7e9ca3e --- /dev/null +++ b/drm/java/android/drm/DrmInfoStatus.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2010 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 android.drm; + +/** + * This is an entity class which wraps the result of communication between device + * and online DRM server. + * + * As a result of {@link DrmManagerClient#processDrmInfo(DrmInfo)} an instance of DrmInfoStatus + * would be returned. This class holds {@link ProcessedData}, which could be used to instantiate + * {@link DrmRights#DrmRights(ProcessedData, String)} in license acquisition. + * + */ +public class DrmInfoStatus { + // Should be in sync with DrmInfoStatus.cpp + public static final int STATUS_OK = 1; + public static final int STATUS_ERROR = 2; + + public final int statusCode; + public final String mimeType; + public final ProcessedData data; + + /** + * constructor to create DrmInfoStatus object with given parameters + * + * @param _statusCode Status of the communication + * @param _data The processed data + * @param _mimeType MIME type + */ + public DrmInfoStatus(int _statusCode, ProcessedData _data, String _mimeType) { + statusCode = _statusCode; + data = _data; + mimeType = _mimeType; + } +} + diff --git a/drm/java/android/drm/DrmManagerClient.java b/drm/java/android/drm/DrmManagerClient.java new file mode 100644 index 0000000..9ee597c --- /dev/null +++ b/drm/java/android/drm/DrmManagerClient.java @@ -0,0 +1,487 @@ +/* + * Copyright (C) 2010 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 android.drm; + +import android.content.ContentValues; +import android.content.Context; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.util.Log; + +import java.io.IOException; +import java.lang.ref.WeakReference; +import java.util.ArrayList; + +/** + * Interface of DRM Framework. + * Java application will instantiate this class + * to access DRM agent through DRM Framework. + * + */ +public class DrmManagerClient { + private static final String TAG = "DrmManager"; + + static { + // Load the respective library + System.loadLibrary("drmframework_jni"); + } + + /** + * Interface definition of a callback to be invoked to communicate + * some info and/or warning about DrmManagerClient. + */ + public interface OnInfoListener { + /** + * Called to indicate an info or a warning. + * + * @param client DrmManagerClient instance + * @param event instance which wraps reason and necessary information + */ + public void onInfo(DrmManagerClient client, DrmInfoEvent event); + } + + private static final int STATE_UNINITIALIZED = 0x00000000; + private static final int STATE_INITIALIZED = 0x00000001; + + private int mUniqueId; + private int mNativeContext; + private EventHandler mEventHandler; + private OnInfoListener mOnInfoListener; + private int mCurrentState = STATE_UNINITIALIZED; + + /** + * {@hide} + */ + public static void notify(Object thisReference, int uniqueId, int infoType, String message) { + DrmManagerClient instance = (DrmManagerClient)((WeakReference)thisReference).get(); + + if (null != instance && null != instance.mEventHandler) { + Message m = instance.mEventHandler.obtainMessage( + EventHandler.INFO_EVENT_TYPE, uniqueId, infoType, message); + instance.mEventHandler.sendMessage(m); + } + } + + private class EventHandler extends Handler { + public static final int INFO_EVENT_TYPE = 1; + + public EventHandler(Looper looper) { + super(looper); + } + + public void handleMessage(Message msg) { + + switch (msg.what) { + case EventHandler.INFO_EVENT_TYPE: + int uniqueId = msg.arg1; + int infoType = msg.arg2; + String message = msg.obj.toString(); + + if (infoType == DrmInfoEvent.TYPE_REMOVE_RIGHTS) { + try { + DrmUtils.removeFile(message); + } catch (IOException e) { + e.printStackTrace(); + } + } + + if (null != mOnInfoListener) { + DrmInfoEvent event = new DrmInfoEvent(uniqueId, infoType, message); + mOnInfoListener.onInfo(DrmManagerClient.this, event); + } + return; + default: + Log.e(TAG, "Unknown message type " + msg.what); + return; + } + } + } + + /** + * To instantiate DrmManagerClient + * + * @param context context of the caller + */ + public DrmManagerClient(Context context) { + Looper looper; + + if (null != (looper = Looper.myLooper())) { + mEventHandler = new EventHandler(looper); + } else if (null != (looper = Looper.getMainLooper())) { + mEventHandler = new EventHandler(looper); + } else { + mEventHandler = null; + } + + // save the unique id + mUniqueId = hashCode(); + } + + /** + * Register a callback to be invoked when the caller required to receive + * necessary information + * + * @param infoListener + */ + public void setOnInfoListener(OnInfoListener infoListener) { + synchronized(this) { + if (null != infoListener) { + mOnInfoListener = infoListener; + } + } + } + + /** + * Initializes DrmFramework, which loads all available plug-ins + * in the default plug-in directory path + * + */ + public void loadPlugIns() { + if (getState() == STATE_UNINITIALIZED) { + _loadPlugIns(mUniqueId, new WeakReference<DrmManagerClient>(this)); + + mCurrentState = STATE_INITIALIZED; + } + } + + /** + * Finalize DrmFramework, which release resources associated with each plug-in + * and unload all plug-ins. + */ + public void unloadPlugIns() { + if (getState() == STATE_INITIALIZED) { + _unloadPlugIns(mUniqueId); + + mCurrentState = STATE_UNINITIALIZED; + } + } + + /** + * Retrieves informations about all the plug-ins registered with DrmFramework. + * + * @return Array of DrmEngine plug-in strings + */ + public String[] getAvailableDrmEngines() { + if (getState() == STATE_UNINITIALIZED) { + throw new IllegalStateException("Not Initialized yet"); + } + + DrmSupportInfo[] supportInfos = _getAllSupportInfo(mUniqueId); + ArrayList<String> descriptions = new ArrayList<String>(); + + for (int i = 0; i < supportInfos.length; i++) { + descriptions.add(supportInfos[i].getDescriprition()); + } + + String[] drmEngines = new String[descriptions.size()]; + return descriptions.toArray(drmEngines); + } + + /** + * Get constraints information evaluated from DRM content + * + * @param path Content path from where DRM constraints would be retrieved. + * @param action Actions defined in {@link DrmStore.Action} + * @return ContentValues instance in which constraints key-value pairs are embedded + * or null in case of failure + */ + public ContentValues getConstraints(String path, int action) { + if (null == path || path.equals("") || !DrmStore.Action.isValid(action)) { + throw new IllegalArgumentException("Given usage or path is invalid/null"); + } else if (getState() == STATE_UNINITIALIZED) { + throw new IllegalStateException("Not Initialized yet"); + } + return _getConstraints(mUniqueId, path, action); + } + + /** + * Save DRM rights to specified rights path + * and make association with content path. + * + * @param drmRights DrmRights to be saved + * @param rightsPath File path where rights to be saved + * @param contentPath File path where content was saved + * @throws IOException if failed to save rights information in the given path + * + * @note In case of OMA or WM-DRM, rightsPath and contentPath could be null + */ + public void saveRights( + DrmRights drmRights, String rightsPath, String contentPath) throws IOException { + if (null == drmRights || !drmRights.isValid() + || null == contentPath || contentPath.equals("")) { + throw new IllegalArgumentException("Given drmRights or contentPath is not valid"); + } else if (getState() == STATE_UNINITIALIZED) { + throw new IllegalStateException("Not Initialized yet"); + } + if (null != rightsPath && !rightsPath.equals("")) { + DrmUtils.writeToFile(rightsPath, drmRights.getData()); + } + _saveRights(mUniqueId, drmRights, rightsPath, contentPath); + } + + /** + * Install new DRM Engine Plug-in at the runtime + * + * @param engineFilePath Path of the plug-in file to be installed + * {@hide} + */ + public void installDrmEngine(String engineFilePath) { + if (null == engineFilePath || engineFilePath.equals("")) { + throw new IllegalArgumentException( + "Given engineFilePath: "+ engineFilePath + "is not valid"); + } else if (getState() == STATE_UNINITIALIZED) { + throw new IllegalStateException("Not Initialized yet"); + } + _installDrmEngine(mUniqueId, engineFilePath); + } + + /** + * Check whether the given mimetype or path can be handled. + * + * @param path Path of the content to be handled + * @param mimeType Mimetype of the object to be handled + * @return + * true - if the given mimeType or path can be handled + * false - cannot be handled. + * @note false will be return in case the state is uninitialized + */ + public boolean canHandle(String path, String mimeType) { + if ((null == path || path.equals("")) && (null == mimeType || mimeType.equals(""))) { + throw new IllegalArgumentException("Path or the mimetype should be non null"); + } else if (getState() == STATE_UNINITIALIZED) { + throw new IllegalStateException("Not Initialized yet"); + } + return _canHandle(mUniqueId, path, mimeType); + } + + /** + * Executes given drm information based on its type + * + * @param drmInfo Information needs to be processed + * @return DrmInfoStatus Instance as a result of processing given input + */ + public DrmInfoStatus processDrmInfo(DrmInfo drmInfo) { + if (null == drmInfo || !drmInfo.isValid()) { + throw new IllegalArgumentException("Given drmInfo is invalid/null"); + } else if (getState() == STATE_UNINITIALIZED) { + throw new IllegalStateException("Not Initialized yet"); + } + return _processDrmInfo(mUniqueId, drmInfo); + } + + /** + * Retrieves necessary information for register, unregister or rights acquisition. + * + * @param drmInfoRequest Request information to retrieve drmInfo + * @return DrmInfo Instance as a result of processing given input + */ + public DrmInfo acquireDrmInfo(DrmInfoRequest drmInfoRequest) { + if (null == drmInfoRequest || !drmInfoRequest.isValid()) { + throw new IllegalArgumentException("Given drmInfoRequest is invalid/null"); + } else if (getState() == STATE_UNINITIALIZED) { + throw new IllegalStateException("Not Initialized yet"); + } + return _acquireDrmInfo(mUniqueId, drmInfoRequest); + } + + /** + * Retrieves the type of the protected object (content, rights, etc..) + * using specified path or mimetype. At least one parameter should be non null + * to retrieve DRM object type + * + * @param path Path of the content or null. + * @param mimeType Mimetype of the content or null. + * @return Type of the DRM content. + * @see DrmStore.DrmObjectType + */ + public int getDrmObjectType(String path, String mimeType) { + if ((null == path || path.equals("")) && (null == mimeType || mimeType.equals(""))) { + throw new IllegalArgumentException("Path or the mimetype should be non null"); + } else if (getState() == STATE_UNINITIALIZED) { + throw new IllegalStateException("Not Initialized yet"); + } + return _getDrmObjectType(mUniqueId, path, mimeType); + } + + /** + * Retrieves the mime type embedded inside the original content + * + * @param path Path of the protected content + * @return Mimetype of the original content, such as "video/mpeg" + */ + public String getOriginalMimeType(String path) { + if (null == path || path.equals("")) { + throw new IllegalArgumentException("Given path should be non null"); + } else if (getState() == STATE_UNINITIALIZED) { + throw new IllegalStateException("Not Initialized yet"); + } + return _getOriginalMimeType(mUniqueId, path); + } + + /** + * Check whether the given content has valid rights or not + * + * @param path Path of the protected content + * @return Status of the rights for the protected content + * @see DrmStore.RightsStatus + */ + public int checkRightsStatus(String path) { + return checkRightsStatus(path, DrmStore.Action.DEFAULT); + } + + /** + * Check whether the given content has valid rights or not for specified action. + * + * @param path Path of the protected content + * @param action Action to perform + * @return Status of the rights for the protected content + * @see DrmStore.RightsStatus + */ + public int checkRightsStatus(String path, int action) { + if (null == path || path.equals("") || !DrmStore.Action.isValid(action)) { + throw new IllegalArgumentException("Given path or action is not valid"); + } else if (getState() == STATE_UNINITIALIZED) { + throw new IllegalStateException("Not Initialized yet"); + } + return _checkRightsStatus(mUniqueId, path, action); + } + + /** + * Removes the rights associated with the given protected content + * + * @param path Path of the protected content + */ + public void removeRights(String path) { + if (null == path || path.equals("")) { + throw new IllegalArgumentException("Given path should be non null"); + } else if (getState() == STATE_UNINITIALIZED) { + throw new IllegalStateException("Not Initialized yet"); + } + _removeRights(mUniqueId, path); + } + + /** + * Removes all the rights information of every plug-in associated with + * DRM framework. Will be used in master reset + */ + public void removeAllRights() { + if (getState() == STATE_UNINITIALIZED) { + throw new IllegalStateException("Not Initialized yet"); + } + _removeAllRights(mUniqueId); + } + + /** + * This API is for Forward Lock based DRM scheme. + * Each time the application tries to download a new DRM file + * which needs to be converted, then the application has to + * begin with calling this API. + * + * @param mimeType Description/MIME type of the input data packet + * @return convert ID which will be used for maintaining convert session. + */ + public int openConvertSession(String mimeType) { + if (null == mimeType || mimeType.equals("")) { + throw new IllegalArgumentException("Path or the mimeType should be non null"); + } else if (getState() == STATE_UNINITIALIZED) { + throw new IllegalStateException("Not Initialized yet"); + } + return _openConvertSession(mUniqueId, mimeType); + } + + /** + * Accepts and converts the input data which is part of DRM file. + * The resultant converted data and the status is returned in the DrmConvertedInfo + * object. This method will be called each time there are new block + * of data received by the application. + * + * @param convertId Handle for the convert session + * @param inputData Input Data which need to be converted + * @return Return object contains the status of the data conversion, + * the output converted data and offset. In this case the + * application will ignore the offset information. + */ + public DrmConvertedStatus convertData(int convertId, byte[] inputData) { + if (null == inputData || 0 >= inputData.length) { + throw new IllegalArgumentException("Given inputData should be non null"); + } else if (getState() == STATE_UNINITIALIZED) { + throw new IllegalStateException("Not Initialized yet"); + } + return _convertData(mUniqueId, convertId, inputData); + } + + /** + * Informs the Drm Agent when there is no more data which need to be converted + * or when an error occurs. Upon successful conversion of the complete data, + * the agent will inform that where the header and body signature + * should be added. This signature appending is needed to integrity + * protect the converted file. + * + * @param convertId Handle for the convert session + * @return Return object contains the status of the data conversion, + * the header and body signature data. It also informs + * the application on which offset these signature data should be appended. + */ + public DrmConvertedStatus closeConvertSession(int convertId) { + if (getState() == STATE_UNINITIALIZED) { + throw new IllegalStateException("Not Initialized yet"); + } + return _closeConvertSession(mUniqueId, convertId); + } + + private int getState() { + return mCurrentState; + } + + // private native interfaces + private native void _loadPlugIns(int uniqueId, Object weak_this); + + private native void _unloadPlugIns(int uniqueId); + + private native void _installDrmEngine(int uniqueId, String engineFilepath); + + private native ContentValues _getConstraints(int uniqueId, String path, int usage); + + private native boolean _canHandle(int uniqueId, String path, String mimeType); + + private native DrmInfoStatus _processDrmInfo(int uniqueId, DrmInfo drmInfo); + + private native DrmInfo _acquireDrmInfo(int uniqueId, DrmInfoRequest drmInfoRequest); + + private native void _saveRights( + int uniqueId, DrmRights drmRights, String rightsPath, String contentPath); + + private native int _getDrmObjectType(int uniqueId, String path, String mimeType); + + private native String _getOriginalMimeType(int uniqueId, String path); + + private native int _checkRightsStatus(int uniqueId, String path, int action); + + private native void _removeRights(int uniqueId, String path); + + private native void _removeAllRights(int uniqueId); + + private native int _openConvertSession(int uniqueId, String mimeType); + + private native DrmConvertedStatus _convertData(int uniqueId, int convertId, byte[] inputData); + + private native DrmConvertedStatus _closeConvertSession(int uniqueId, int convertId); + + private native DrmSupportInfo[] _getAllSupportInfo(int uniqueId); +} + diff --git a/drm/java/android/drm/DrmRights.java b/drm/java/android/drm/DrmRights.java new file mode 100644 index 0000000..103af07 --- /dev/null +++ b/drm/java/android/drm/DrmRights.java @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2010 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 android.drm; + +import java.io.File; +import java.io.IOException; + +/** + * This is an entity class which wraps the license information which was + * retrieved from the online DRM server. + * + * Caller can instantiate {@link DrmRights} by + * invoking {@link DrmRights#DrmRights(ProcessedData, String)} + * constructor by using the result of {@link DrmManagerClient#processDrmInfo(DrmInfo)} interface. + * Caller can also instantiate {@link DrmRights} using the file path + * which contains rights information. + * + */ +public class DrmRights { + private byte[] mData; + private String mMimeType; + private String mAccountId = "_NO_USER"; + private String mSubscriptionId = ""; + + /** + * constructor to create DrmRights object with given parameters + * + * @param rightsFilePath Path of the file containing rights data + * @param mimeType MIME type + */ + public DrmRights(String rightsFilePath, String mimeType) { + File file = new File(rightsFilePath); + instantiate(file, mimeType); + } + + /** + * constructor to create DrmRights object with given parameters + * + * @param rightsFilePath Path of the file containing rights data + * @param mimeType MIME type + * @param accountId Account Id of the user + */ + public DrmRights(String rightsFilePath, String mimeType, String accountId) { + this(rightsFilePath, mimeType); + + if (null != accountId && !accountId.equals("")) { + mAccountId = accountId; + } + } + + /** + * constructor to create DrmRights object with given parameters + * + * @param rightsFilePath Path of the file containing rights data + * @param mimeType MIME type + * @param accountId Account Id of the user + * @param subscriptionId Subscription Id of the user + */ + public DrmRights( + String rightsFilePath, String mimeType, String accountId, String subscriptionId) { + this(rightsFilePath, mimeType); + + if (null != accountId && !accountId.equals("")) { + mAccountId = accountId; + } + + if (null != subscriptionId && !subscriptionId.equals("")) { + mSubscriptionId = subscriptionId; + } + } + + /** + * constructor to create DrmRights object with given parameters + * + * @param rightsFile File containing rights data + * @param mimeType MIME type + */ + public DrmRights(File rightsFile, String mimeType) { + instantiate(rightsFile, mimeType); + } + + private void instantiate(File rightsFile, String mimeType) { + try { + mData = DrmUtils.readBytes(rightsFile); + } catch (IOException e) { + e.printStackTrace(); + } + + mMimeType = mimeType; + } + + /** + * constructor to create DrmRights object with given parameters + * The user can pass String or binary data<p> + * Usage:<p> + * i) String(e.g. data is instance of String):<br> + * - new DrmRights(data.getBytes(), mimeType)<p> + * ii) Binary data<br> + * - new DrmRights(binaryData[], mimeType)<br> + * + * @param data Processed data + * @param mimeType MIME type + */ + public DrmRights(ProcessedData data, String mimeType) { + mData = data.getData(); + + String accountId = data.getAccountId(); + if (null != accountId && !accountId.equals("")) { + mAccountId = accountId; + } + + String subscriptionId = data.getSubscriptionId(); + if (null != subscriptionId && !subscriptionId.equals("")) { + mSubscriptionId = subscriptionId; + } + + mMimeType = mimeType; + } + + /** + * Returns the rights data associated with this object + * + * @return Rights data + */ + public byte[] getData() { + return mData; + } + + /** + * Returns the mimetype associated with this object + * + * @return MIME type + */ + public String getMimeType() { + return mMimeType; + } + + /** + * Returns the account-id associated with this object + * + * @return Account Id + */ + public String getAccountId() { + return mAccountId; + } + + /** + * Returns the subscription-id associated with this object + * + * @return Subscription Id + */ + public String getSubscriptionId() { + return mSubscriptionId; + } + + /** + * Returns whether this instance is valid or not + * + * @return + * true if valid + * false if invalid + */ + /*package*/ boolean isValid() { + return (null != mMimeType && !mMimeType.equals("") + && null != mData && mData.length > 0); + } +} + diff --git a/drm/java/android/drm/DrmStore.java b/drm/java/android/drm/DrmStore.java new file mode 100644 index 0000000..44df90c --- /dev/null +++ b/drm/java/android/drm/DrmStore.java @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2010 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 android.drm; + +/** + * This class defines all the constants used by DRM framework + * + */ +public class DrmStore { + /** + * Columns representing drm constraints + */ + public interface ConstraintsColumns { + /** + * The max repeat count + * <P>Type: INTEGER</P> + */ + public static final String MAX_REPEAT_COUNT = "max_repeat_count"; + + /** + * The remaining repeat count + * <P>Type: INTEGER</P> + */ + public static final String REMAINING_REPEAT_COUNT = "remaining_repeat_count"; + + /** + * The time before which the protected file can not be played/viewed + * <P>Type: TEXT</P> + */ + public static final String LICENSE_START_TIME = "license_start_time"; + + /** + * The time after which the protected file can not be played/viewed + * <P>Type: TEXT</P> + */ + public static final String LICENSE_EXPIRY_TIME = "license_expiry_time"; + + /** + * The available time for license + * <P>Type: TEXT</P> + */ + public static final String LICENSE_AVAILABLE_TIME = "license_available_time"; + + /** + * The data stream for extended metadata + * <P>Type: TEXT</P> + */ + public static final String EXTENDED_METADATA = "extended_metadata"; + } + + /** + * Defines constants related to DRM types + */ + public static class DrmObjectType { + /** + * Field specifies the unknown type + */ + public static final int UNKNOWN = 0x00; + /** + * Field specifies the protected content type + */ + public static final int CONTENT = 0x01; + /** + * Field specifies the rights information + */ + public static final int RIGHTS_OBJECT = 0x02; + /** + * Field specifies the trigger information + */ + public static final int TRIGGER_OBJECT = 0x03; + } + + /** + * Defines constants related to playback + */ + public static class Playback { + /** + * Constant field signifies playback start + */ + public static final int START = 0x00; + /** + * Constant field signifies playback stop + */ + public static final int STOP = 0x01; + /** + * Constant field signifies playback paused + */ + public static final int PAUSE = 0x02; + /** + * Constant field signifies playback resumed + */ + public static final int RESUME = 0x03; + + /* package */ static boolean isValid(int playbackStatus) { + boolean isValid = false; + + switch (playbackStatus) { + case START: + case STOP: + case PAUSE: + case RESUME: + isValid = true; + } + return isValid; + } + } + + /** + * Defines actions that can be performed on protected content + */ + public static class Action { + /** + * Constant field signifies that the default action + */ + public static final int DEFAULT = 0x00; + /** + * Constant field signifies that the content can be played + */ + public static final int PLAY = 0x01; + /** + * Constant field signifies that the content can be set as ring tone + */ + public static final int RINGTONE = 0x02; + /** + * Constant field signifies that the content can be transfered + */ + public static final int TRANSFER = 0x03; + /** + * Constant field signifies that the content can be set as output + */ + public static final int OUTPUT = 0x04; + /** + * Constant field signifies that preview is allowed + */ + public static final int PREVIEW = 0x05; + /** + * Constant field signifies that the content can be executed + */ + public static final int EXECUTE = 0x06; + /** + * Constant field signifies that the content can displayed + */ + public static final int DISPLAY = 0x07; + + /* package */ static boolean isValid(int action) { + boolean isValid = false; + + switch (action) { + case DEFAULT: + case PLAY: + case RINGTONE: + case TRANSFER: + case OUTPUT: + case PREVIEW: + case EXECUTE: + case DISPLAY: + isValid = true; + } + return isValid; + } + } + + /** + * Defines constants related to status of the rights + */ + public static class RightsStatus { + /** + * Constant field signifies that the rights are valid + */ + public static final int RIGHTS_VALID = 0x00; + /** + * Constant field signifies that the rights are invalid + */ + public static final int RIGHTS_INVALID = 0x01; + /** + * Constant field signifies that the rights are expired for the content + */ + public static final int RIGHTS_EXPIRED = 0x02; + /** + * Constant field signifies that the rights are not acquired for the content + */ + public static final int RIGHTS_NOT_ACQUIRED = 0x03; + } +} + diff --git a/drm/java/android/drm/DrmSupportInfo.java b/drm/java/android/drm/DrmSupportInfo.java new file mode 100644 index 0000000..0886af8 --- /dev/null +++ b/drm/java/android/drm/DrmSupportInfo.java @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2010 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 android.drm; + +import java.util.ArrayList; +import java.util.Iterator; + +/** + * This is an entity class which wraps the capability of each plug-in, + * such as mimetype's and file suffixes it could handle. + * + * Plug-in developer could return the capability of the plugin by passing + * {@link DrmSupportInfo} instance. + * + */ +public class DrmSupportInfo { + private final ArrayList<String> mFileSuffixList = new ArrayList<String>(); + private final ArrayList<String> mMimeTypeList = new ArrayList<String>(); + private String mDescription = ""; + + /** + * Add the mime-type to the support info such that respective plug-in is + * capable of handling the given mime-type. + * + * @param mimeType MIME type + */ + public void addMimeType(String mimeType) { + mMimeTypeList.add(mimeType); + } + + /** + * Add the file suffix to the support info such that respective plug-in is + * capable of handling the given file suffix. + * + * @param fileSuffix File suffix which can be handled + */ + public void addFileSuffix(String fileSuffix) { + mFileSuffixList.add(fileSuffix); + } + + /** + * Returns the iterator to walk to through mime types of this object + * + * @return Iterator object + */ + public Iterator<String> getMimeTypeIterator() { + return mMimeTypeList.iterator(); + } + + /** + * Returns the iterator to walk to through file suffixes of this object + * + * @return Iterator object + */ + public Iterator<String> getFileSuffixIterator() { + return mFileSuffixList.iterator(); + } + + /** + * Set the unique description about the plugin + * + * @param description Unique description + */ + public void setDescription(String description) { + if (null != description) { + mDescription = description; + } + } + + /** + * Returns the unique description associated with the plugin + * + * @return Unique description + */ + public String getDescriprition() { + return mDescription; + } + + /** + * Overridden hash code implementation + * + * @return Hash code value + */ + public int hashCode() { + return mFileSuffixList.hashCode() + mMimeTypeList.hashCode() + mDescription.hashCode(); + } + + /** + * Overridden equals implementation + * + * @param object The object to be compared + * @return + * true if equal + * false if not equal + */ + public boolean equals(Object object) { + boolean result = false; + + if (object instanceof DrmSupportInfo) { + result = mFileSuffixList.equals(((DrmSupportInfo) object).mFileSuffixList) && + mMimeTypeList.equals(((DrmSupportInfo) object).mMimeTypeList) && + mDescription.equals(((DrmSupportInfo) object).mDescription); + } + return result; + } + + /** + * Returns whether given mime-type is supported or not + * + * @param mimeType MIME type + * @return + * true if mime type is supported + * false if mime type is not supported + */ + /* package */ boolean isSupportedMimeType(String mimeType) { + if (null != mimeType && !mimeType.equals("")) { + for (int i = 0; i < mMimeTypeList.size(); i++) { + String completeMimeType = mMimeTypeList.get(i); + if (completeMimeType.startsWith(mimeType)) { + return true; + } + } + } + return false; + } + + /** + * Returns whether given file suffix is supported or not + * + * @param fileSuffix File suffix + * @return + * true - if file suffix is supported + * false - if file suffix is not supported + */ + /* package */ boolean isSupportedFileSuffix(String fileSuffix) { + return mFileSuffixList.contains(fileSuffix); + } +} + diff --git a/drm/java/android/drm/DrmUtils.java b/drm/java/android/drm/DrmUtils.java new file mode 100644 index 0000000..5e5397c --- /dev/null +++ b/drm/java/android/drm/DrmUtils.java @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2010 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 android.drm; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.HashMap; +import java.util.Iterator; + +/** + * The utility class used in the DRM Framework. This inclueds APIs for file operations + * and ExtendedMetadataParser for parsing extended metadata BLOB in DRM constraints. + * + */ +public class DrmUtils { + /* Should be used when we need to read from local file */ + /* package */ static byte[] readBytes(String path) throws IOException { + File file = new File(path); + return readBytes(file); + } + + /* Should be used when we need to read from local file */ + /* package */ static byte[] readBytes(File file) throws IOException { + FileInputStream inputStream = new FileInputStream(file); + BufferedInputStream bufferedStream = new BufferedInputStream(inputStream); + byte[] data = null; + + try { + int length = bufferedStream.available(); + if (length > 0) { + data = new byte[length]; + // read the entire data + bufferedStream.read(data); + } + } finally { + quiteDispose(bufferedStream); + quiteDispose(inputStream); + } + return data; + } + + /* package */ static void writeToFile(final String path, byte[] data) throws IOException { + /* check for invalid inputs */ + FileOutputStream outputStream = null; + + if (null != path && null != data) { + try { + outputStream = new FileOutputStream(path); + outputStream.write(data); + } finally { + quiteDispose(outputStream); + } + } + } + + /* package */ static void removeFile(String path) throws IOException { + File file = new File(path); + file.delete(); + } + + private static void quiteDispose(InputStream stream) { + try { + if (null != stream) { + stream.close(); + } + } catch (IOException e) { + // no need to care, at least as of now + } + } + + private static void quiteDispose(OutputStream stream) { + try { + if (null != stream) { + stream.close(); + } + } catch (IOException e) { + // no need to care + } + } + + /** + * Get an instance of ExtendedMetadataParser to be used for parsing + * extended metadata BLOB in DRM constraints. <br> + * + * extendedMetadata BLOB is retrieved by specifing + * key DrmStore.ConstraintsColumns.EXTENDED_METADATA. + * + * @param extendedMetadata BLOB in which key-value pairs of extended metadata are embedded. + * + */ + public static ExtendedMetadataParser getExtendedMetadataParser(byte[] extendedMetadata) { + return new ExtendedMetadataParser(extendedMetadata); + } + + /** + * Utility parser to parse the extended meta-data embedded inside DRM constraints<br><br> + * + * Usage example<br> + * byte[] extendedMetadata<br> + * = + * constraints.getAsByteArray(DrmStore.ConstraintsColumns.EXTENDED_METADATA);<br> + * ExtendedMetadataParser parser = getExtendedMetadataParser(extendedMetadata);<br> + * Iterator keyIterator = parser.keyIterator();<br> + * while (keyIterator.hasNext()) {<br> + * String extendedMetadataKey = keyIterator.next();<br> + * String extendedMetadataValue = + * parser.get(extendedMetadataKey);<br> + * } + */ + public static class ExtendedMetadataParser { + HashMap<String, String> mMap = new HashMap<String, String>(); + + private int readByte(byte[] constraintData, int arrayIndex) { + //Convert byte[] into int. + return (int)constraintData[arrayIndex]; + } + + private String readMultipleBytes( + byte[] constraintData, int numberOfBytes, int arrayIndex) { + byte[] returnBytes = new byte[numberOfBytes]; + for (int j = arrayIndex, i = 0; j < arrayIndex + numberOfBytes; j++,i++) { + returnBytes[i] = constraintData[j]; + } + return new String(returnBytes); + } + + /* + * This will parse the following format + * KeyLengthValueLengthKeyValueKeyLength1ValueLength1Key1Value1..\0 + */ + private ExtendedMetadataParser(byte[] constraintData) { + //Extract KeyValue Pair Info, till terminator occurs. + int index = 0; + + while (index < constraintData.length) { + //Parse Key Length + int keyLength = readByte(constraintData, index); + index++; + + //Parse Value Length + int valueLength = readByte(constraintData, index); + index++; + + //Fetch key + String strKey = readMultipleBytes(constraintData, keyLength, index); + index += keyLength; + + //Fetch Value + String strValue = readMultipleBytes(constraintData, valueLength, index); + index += valueLength; + mMap.put(strKey, strValue); + } + } + + public Iterator<String> iterator() { + return mMap.values().iterator(); + } + + public Iterator<String> keyIterator() { + return mMap.keySet().iterator(); + } + + public String get(String key) { + return mMap.get(key); + } + } +} + diff --git a/drm/java/android/drm/ProcessedData.java b/drm/java/android/drm/ProcessedData.java new file mode 100644 index 0000000..579264f --- /dev/null +++ b/drm/java/android/drm/ProcessedData.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2010 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 android.drm; + +/** + * This is an entity class which wraps the result of transaction between + * device and online DRM server by using {@link DrmManagerClient#processDrmInfo(DrmInfo)} + * + * In license acquisition scenario this class would hold the binary data + * of rights information. + * + */ +public class ProcessedData { + private final byte[] mData; + private String mAccountId = "_NO_USER"; + private String mSubscriptionId = ""; + + /** + * constructor to create ProcessedData object with given parameters + * + * @param data Rights data + * @param accountId Account Id of the user + */ + /* package */ ProcessedData(byte[] data, String accountId) { + mData = data; + mAccountId = accountId; + } + + /** + * constructor to create ProcessedData object with given parameters + * + * @param data Rights data + * @param accountId Account Id of the user + * @param subscriptionId Subscription Id of the user + */ + /* package */ ProcessedData(byte[] data, String accountId, String subscriptionId) { + mData = data; + mAccountId = accountId; + mSubscriptionId = subscriptionId; + } + + /** + * Returns the processed data as a result. + * + * @return Rights data associated + */ + public byte[] getData() { + return mData; + } + + /** + * Returns the account-id associated with this object + * + * @return Account Id associated + */ + public String getAccountId() { + return mAccountId; + } + + /** + * Returns the subscription-id associated with this object + * + * @return Subscription Id associated + */ + public String getSubscriptionId() { + return mSubscriptionId; + } +} + |