Home | History | Annotate | Download | only in drm
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.drm;
     18 
     19 import android.content.ContentResolver;
     20 import android.content.ContentValues;
     21 import android.content.Context;
     22 import android.database.Cursor;
     23 import android.database.sqlite.SQLiteException;
     24 import android.net.Uri;
     25 import android.os.Handler;
     26 import android.os.HandlerThread;
     27 import android.os.Looper;
     28 import android.os.Message;
     29 import android.provider.MediaStore;
     30 import android.util.Log;
     31 
     32 import dalvik.system.CloseGuard;
     33 
     34 import java.io.File;
     35 import java.io.FileDescriptor;
     36 import java.io.FileInputStream;
     37 import java.io.IOException;
     38 import java.lang.ref.WeakReference;
     39 import java.util.ArrayList;
     40 import java.util.HashMap;
     41 
     42 /**
     43  * The main programming interface for the DRM framework. An application must instantiate this class
     44  * to access DRM agents through the DRM framework.
     45  *
     46  */
     47 public class DrmManagerClient {
     48     /**
     49      * Indicates that a request was successful or that no error occurred.
     50      */
     51     public static final int ERROR_NONE = 0;
     52     /**
     53      * Indicates that an error occurred and the reason is not known.
     54      */
     55     public static final int ERROR_UNKNOWN = -2000;
     56 
     57     /** {@hide} */
     58     public static final int INVALID_SESSION = -1;
     59 
     60     HandlerThread mInfoThread;
     61     HandlerThread mEventThread;
     62     private static final String TAG = "DrmManagerClient";
     63 
     64     private final CloseGuard mCloseGuard = CloseGuard.get();
     65 
     66     static {
     67         // Load the respective library
     68         System.loadLibrary("drmframework_jni");
     69     }
     70 
     71     /**
     72      * Interface definition for a callback that receives status messages and warnings
     73      * during registration and rights acquisition.
     74      */
     75     public interface OnInfoListener {
     76         /**
     77          * Called when the DRM framework sends status or warning information during registration
     78          * and rights acquisition.
     79          *
     80          * @param client The <code>DrmManagerClient</code> instance.
     81          * @param event The {@link DrmInfoEvent} instance that wraps the status information or
     82          * warnings.
     83          */
     84         public void onInfo(DrmManagerClient client, DrmInfoEvent event);
     85     }
     86 
     87     /**
     88      * Interface definition for a callback that receives information
     89      * about DRM processing events.
     90      */
     91     public interface OnEventListener {
     92         /**
     93          * Called when the DRM framework sends information about a DRM processing request.
     94          *
     95          * @param client The <code>DrmManagerClient</code> instance.
     96          * @param event The {@link DrmEvent} instance that wraps the information being
     97          * conveyed, such as the information type and message.
     98          */
     99         public void onEvent(DrmManagerClient client, DrmEvent event);
    100     }
    101 
    102     /**
    103      * Interface definition for a callback that receives information about DRM framework errors.
    104      */
    105     public interface OnErrorListener {
    106         /**
    107          * Called when the DRM framework sends error information.
    108          *
    109          * @param client The <code>DrmManagerClient</code> instance.
    110          * @param event The {@link DrmErrorEvent} instance that wraps the error type and message.
    111          */
    112         public void onError(DrmManagerClient client, DrmErrorEvent event);
    113     }
    114 
    115     private static final int ACTION_REMOVE_ALL_RIGHTS = 1001;
    116     private static final int ACTION_PROCESS_DRM_INFO = 1002;
    117 
    118     private int mUniqueId;
    119     private long mNativeContext;
    120     private volatile boolean mReleased;
    121     private Context mContext;
    122     private InfoHandler mInfoHandler;
    123     private EventHandler mEventHandler;
    124     private OnInfoListener mOnInfoListener;
    125     private OnEventListener mOnEventListener;
    126     private OnErrorListener mOnErrorListener;
    127 
    128     private class EventHandler extends Handler {
    129 
    130         public EventHandler(Looper looper) {
    131             super(looper);
    132         }
    133 
    134         public void handleMessage(Message msg) {
    135             DrmEvent event = null;
    136             DrmErrorEvent error = null;
    137             HashMap<String, Object> attributes = new HashMap<String, Object>();
    138 
    139             switch(msg.what) {
    140             case ACTION_PROCESS_DRM_INFO: {
    141                 final DrmInfo drmInfo = (DrmInfo) msg.obj;
    142                 DrmInfoStatus status = _processDrmInfo(mUniqueId, drmInfo);
    143 
    144                 attributes.put(DrmEvent.DRM_INFO_STATUS_OBJECT, status);
    145                 attributes.put(DrmEvent.DRM_INFO_OBJECT, drmInfo);
    146 
    147                 if (null != status && DrmInfoStatus.STATUS_OK == status.statusCode) {
    148                     event = new DrmEvent(mUniqueId,
    149                             getEventType(status.infoType), null, attributes);
    150                 } else {
    151                     int infoType = (null != status) ? status.infoType : drmInfo.getInfoType();
    152                     error = new DrmErrorEvent(mUniqueId,
    153                             getErrorType(infoType), null, attributes);
    154                 }
    155                 break;
    156             }
    157             case ACTION_REMOVE_ALL_RIGHTS: {
    158                 if (ERROR_NONE == _removeAllRights(mUniqueId)) {
    159                     event = new DrmEvent(mUniqueId, DrmEvent.TYPE_ALL_RIGHTS_REMOVED, null);
    160                 } else {
    161                     error = new DrmErrorEvent(mUniqueId,
    162                             DrmErrorEvent.TYPE_REMOVE_ALL_RIGHTS_FAILED, null);
    163                 }
    164                 break;
    165             }
    166             default:
    167                 Log.e(TAG, "Unknown message type " + msg.what);
    168                 return;
    169             }
    170             if (null != mOnEventListener && null != event) {
    171                 mOnEventListener.onEvent(DrmManagerClient.this, event);
    172             }
    173             if (null != mOnErrorListener && null != error) {
    174                 mOnErrorListener.onError(DrmManagerClient.this, error);
    175             }
    176         }
    177     }
    178 
    179     /**
    180      * {@hide}
    181      */
    182     public static void notify(
    183             Object thisReference, int uniqueId, int infoType, String message) {
    184         DrmManagerClient instance = (DrmManagerClient)((WeakReference)thisReference).get();
    185 
    186         if (null != instance && null != instance.mInfoHandler) {
    187             Message m = instance.mInfoHandler.obtainMessage(
    188                 InfoHandler.INFO_EVENT_TYPE, uniqueId, infoType, message);
    189             instance.mInfoHandler.sendMessage(m);
    190         }
    191     }
    192 
    193     private class InfoHandler extends Handler {
    194         public static final int INFO_EVENT_TYPE = 1;
    195 
    196         public InfoHandler(Looper looper) {
    197             super(looper);
    198         }
    199 
    200         public void handleMessage(Message msg) {
    201             DrmInfoEvent info = null;
    202             DrmErrorEvent error = null;
    203 
    204             switch (msg.what) {
    205             case InfoHandler.INFO_EVENT_TYPE:
    206                 int uniqueId = msg.arg1;
    207                 int infoType = msg.arg2;
    208                 String message = msg.obj.toString();
    209 
    210                 switch (infoType) {
    211                 case DrmInfoEvent.TYPE_REMOVE_RIGHTS: {
    212                     try {
    213                         DrmUtils.removeFile(message);
    214                     } catch (IOException e) {
    215                         e.printStackTrace();
    216                     }
    217                     info = new DrmInfoEvent(uniqueId, infoType, message);
    218                     break;
    219                 }
    220                 case DrmInfoEvent.TYPE_ALREADY_REGISTERED_BY_ANOTHER_ACCOUNT:
    221                 case DrmInfoEvent.TYPE_RIGHTS_INSTALLED:
    222                 case DrmInfoEvent.TYPE_WAIT_FOR_RIGHTS:
    223                 case DrmInfoEvent.TYPE_ACCOUNT_ALREADY_REGISTERED:
    224                 case DrmInfoEvent.TYPE_RIGHTS_REMOVED: {
    225                     info = new DrmInfoEvent(uniqueId, infoType, message);
    226                     break;
    227                 }
    228                 default:
    229                     error = new DrmErrorEvent(uniqueId, infoType, message);
    230                     break;
    231                 }
    232 
    233                 if (null != mOnInfoListener && null != info) {
    234                     mOnInfoListener.onInfo(DrmManagerClient.this, info);
    235                 }
    236                 if (null != mOnErrorListener && null != error) {
    237                     mOnErrorListener.onError(DrmManagerClient.this, error);
    238                 }
    239                 return;
    240             default:
    241                 Log.e(TAG, "Unknown message type " + msg.what);
    242                 return;
    243             }
    244         }
    245     }
    246 
    247     /**
    248      * Creates a <code>DrmManagerClient</code>.
    249      *
    250      * @param context Context of the caller.
    251      */
    252     public DrmManagerClient(Context context) {
    253         mContext = context;
    254         createEventThreads();
    255 
    256         // save the unique id
    257         mUniqueId = _initialize();
    258         mCloseGuard.open("release");
    259     }
    260 
    261     @Override
    262     protected void finalize() throws Throwable {
    263         try {
    264             if (mCloseGuard != null) {
    265                 mCloseGuard.warnIfOpen();
    266             }
    267             release();
    268         } finally {
    269             super.finalize();
    270         }
    271     }
    272 
    273     /**
    274      * Releases resources associated with the current session of DrmManagerClient.
    275      *
    276      * It is considered good practice to call this method when the {@link DrmManagerClient} object
    277      * is no longer needed in your application. After release() is called,
    278      * {@link DrmManagerClient} is no longer usable since it has lost all of its required resource.
    279      */
    280     public void release() {
    281         if (mReleased) return;
    282         mReleased = true;
    283 
    284         if (mEventHandler != null) {
    285             mEventThread.quit();
    286             mEventThread = null;
    287         }
    288         if (mInfoHandler != null) {
    289             mInfoThread.quit();
    290             mInfoThread = null;
    291         }
    292         mEventHandler = null;
    293         mInfoHandler = null;
    294         mOnEventListener = null;
    295         mOnInfoListener = null;
    296         mOnErrorListener = null;
    297         _release(mUniqueId);
    298         mCloseGuard.close();
    299     }
    300 
    301     /**
    302      * Registers an {@link DrmManagerClient.OnInfoListener} callback, which is invoked when the
    303      * DRM framework sends status or warning information during registration or rights acquisition.
    304      *
    305      * @param infoListener Interface definition for the callback.
    306      */
    307     public synchronized void setOnInfoListener(OnInfoListener infoListener) {
    308         mOnInfoListener = infoListener;
    309         if (null != infoListener) {
    310             createListeners();
    311         }
    312     }
    313 
    314     /**
    315      * Registers an {@link DrmManagerClient.OnEventListener} callback, which is invoked when the
    316      * DRM framework sends information about DRM processing.
    317      *
    318      * @param eventListener Interface definition for the callback.
    319      */
    320     public synchronized void setOnEventListener(OnEventListener eventListener) {
    321         mOnEventListener = eventListener;
    322         if (null != eventListener) {
    323             createListeners();
    324         }
    325     }
    326 
    327     /**
    328      * Registers an {@link DrmManagerClient.OnErrorListener} callback, which is invoked when
    329      * the DRM framework sends error information.
    330      *
    331      * @param errorListener Interface definition for the callback.
    332      */
    333     public synchronized void setOnErrorListener(OnErrorListener errorListener) {
    334         mOnErrorListener = errorListener;
    335         if (null != errorListener) {
    336             createListeners();
    337         }
    338     }
    339 
    340     /**
    341      * Retrieves information about all the DRM plug-ins (agents) that are registered with
    342      * the DRM framework.
    343      *
    344      * @return A <code>String</code> array of DRM plug-in descriptions.
    345      */
    346     public String[] getAvailableDrmEngines() {
    347         DrmSupportInfo[] supportInfos = _getAllSupportInfo(mUniqueId);
    348         ArrayList<String> descriptions = new ArrayList<String>();
    349 
    350         for (int i = 0; i < supportInfos.length; i++) {
    351             descriptions.add(supportInfos[i].getDescriprition());
    352         }
    353 
    354         String[] drmEngines = new String[descriptions.size()];
    355         return descriptions.toArray(drmEngines);
    356     }
    357 
    358     /**
    359      * Retrieves constraint information for rights-protected content.
    360      *
    361      * @param path Path to the content from which you are retrieving DRM constraints.
    362      * @param action Action defined in {@link DrmStore.Action}.
    363      *
    364      * @return A {@link android.content.ContentValues} instance that contains
    365      * key-value pairs representing the constraints. Null in case of failure.
    366      * The keys are defined in {@link DrmStore.ConstraintsColumns}.
    367      */
    368     public ContentValues getConstraints(String path, int action) {
    369         if (null == path || path.equals("") || !DrmStore.Action.isValid(action)) {
    370             throw new IllegalArgumentException("Given usage or path is invalid/null");
    371         }
    372         return _getConstraints(mUniqueId, path, action);
    373     }
    374 
    375    /**
    376     * Retrieves metadata information for rights-protected content.
    377     *
    378     * @param path Path to the content from which you are retrieving metadata information.
    379     *
    380     * @return A {@link android.content.ContentValues} instance that contains
    381     * key-value pairs representing the metadata. Null in case of failure.
    382     */
    383     public ContentValues getMetadata(String path) {
    384         if (null == path || path.equals("")) {
    385             throw new IllegalArgumentException("Given path is invalid/null");
    386         }
    387         return _getMetadata(mUniqueId, path);
    388     }
    389 
    390     /**
    391      * Retrieves constraint information for rights-protected content.
    392      *
    393      * @param uri URI for the content from which you are retrieving DRM constraints.
    394      * @param action Action defined in {@link DrmStore.Action}.
    395      *
    396      * @return A {@link android.content.ContentValues} instance that contains
    397      * key-value pairs representing the constraints. Null in case of failure.
    398      */
    399     public ContentValues getConstraints(Uri uri, int action) {
    400         if (null == uri || Uri.EMPTY == uri) {
    401             throw new IllegalArgumentException("Uri should be non null");
    402         }
    403         return getConstraints(convertUriToPath(uri), action);
    404     }
    405 
    406    /**
    407     * Retrieves metadata information for rights-protected content.
    408     *
    409     * @param uri URI for the content from which you are retrieving metadata information.
    410     *
    411     * @return A {@link android.content.ContentValues} instance that contains
    412     * key-value pairs representing the constraints. Null in case of failure.
    413     */
    414     public ContentValues getMetadata(Uri uri) {
    415         if (null == uri || Uri.EMPTY == uri) {
    416             throw new IllegalArgumentException("Uri should be non null");
    417         }
    418         return getMetadata(convertUriToPath(uri));
    419     }
    420 
    421     /**
    422      * Saves rights to a specified path and associates that path with the content path.
    423      *
    424      * <p class="note"><strong>Note:</strong> For OMA or WM-DRM, <code>rightsPath</code> and
    425      * <code>contentPath</code> can be null.</p>
    426      *
    427      * @param drmRights The {@link DrmRights} to be saved.
    428      * @param rightsPath File path where rights will be saved.
    429      * @param contentPath File path where content is saved.
    430      *
    431      * @return ERROR_NONE for success; ERROR_UNKNOWN for failure.
    432      *
    433      * @throws IOException If the call failed to save rights information at the given
    434      * <code>rightsPath</code>.
    435      */
    436     public int saveRights(
    437             DrmRights drmRights, String rightsPath, String contentPath) throws IOException {
    438         if (null == drmRights || !drmRights.isValid()) {
    439             throw new IllegalArgumentException("Given drmRights or contentPath is not valid");
    440         }
    441         if (null != rightsPath && !rightsPath.equals("")) {
    442             DrmUtils.writeToFile(rightsPath, drmRights.getData());
    443         }
    444         return _saveRights(mUniqueId, drmRights, rightsPath, contentPath);
    445     }
    446 
    447     /**
    448      * Installs a new DRM plug-in (agent) at runtime.
    449      *
    450      * @param engineFilePath File path to the plug-in file to be installed.
    451      *
    452      * {@hide}
    453      */
    454     public void installDrmEngine(String engineFilePath) {
    455         if (null == engineFilePath || engineFilePath.equals("")) {
    456             throw new IllegalArgumentException(
    457                 "Given engineFilePath: "+ engineFilePath + "is not valid");
    458         }
    459         _installDrmEngine(mUniqueId, engineFilePath);
    460     }
    461 
    462     /**
    463      * Checks whether the given MIME type or path can be handled.
    464      *
    465      * @param path Path of the content to be handled.
    466      * @param mimeType MIME type of the object to be handled.
    467      *
    468      * @return True if the given MIME type or path can be handled; false if they cannot be handled.
    469      */
    470     public boolean canHandle(String path, String mimeType) {
    471         if ((null == path || path.equals("")) && (null == mimeType || mimeType.equals(""))) {
    472             throw new IllegalArgumentException("Path or the mimetype should be non null");
    473         }
    474         return _canHandle(mUniqueId, path, mimeType);
    475     }
    476 
    477     /**
    478      * Checks whether the given MIME type or URI can be handled.
    479      *
    480      * @param uri URI for the content to be handled.
    481      * @param mimeType MIME type of the object to be handled
    482      *
    483      * @return True if the given MIME type or URI can be handled; false if they cannot be handled.
    484      */
    485     public boolean canHandle(Uri uri, String mimeType) {
    486         if ((null == uri || Uri.EMPTY == uri) && (null == mimeType || mimeType.equals(""))) {
    487             throw new IllegalArgumentException("Uri or the mimetype should be non null");
    488         }
    489         return canHandle(convertUriToPath(uri), mimeType);
    490     }
    491 
    492     /**
    493      * Processes the given DRM information based on the information type.
    494      *
    495      * @param drmInfo The {@link DrmInfo} to be processed.
    496      * @return ERROR_NONE for success; ERROR_UNKNOWN for failure.
    497      */
    498     public int processDrmInfo(DrmInfo drmInfo) {
    499         if (null == drmInfo || !drmInfo.isValid()) {
    500             throw new IllegalArgumentException("Given drmInfo is invalid/null");
    501         }
    502         int result = ERROR_UNKNOWN;
    503         if (null != mEventHandler) {
    504             Message msg = mEventHandler.obtainMessage(ACTION_PROCESS_DRM_INFO, drmInfo);
    505             result = (mEventHandler.sendMessage(msg)) ? ERROR_NONE : result;
    506         }
    507         return result;
    508     }
    509 
    510     /**
    511      * Retrieves information for registering, unregistering, or acquiring rights.
    512      *
    513      * @param drmInfoRequest The {@link DrmInfoRequest} that specifies the type of DRM
    514      * information being retrieved.
    515      *
    516      * @return A {@link DrmInfo} instance.
    517      */
    518     public DrmInfo acquireDrmInfo(DrmInfoRequest drmInfoRequest) {
    519         if (null == drmInfoRequest || !drmInfoRequest.isValid()) {
    520             throw new IllegalArgumentException("Given drmInfoRequest is invalid/null");
    521         }
    522         return _acquireDrmInfo(mUniqueId, drmInfoRequest);
    523     }
    524 
    525     /**
    526      * Processes a given {@link DrmInfoRequest} and returns the rights information asynchronously.
    527      *<p>
    528      * This is a utility method that consists of an
    529      * {@link #acquireDrmInfo(DrmInfoRequest) acquireDrmInfo()} and a
    530      * {@link #processDrmInfo(DrmInfo) processDrmInfo()} method call. This utility method can be
    531      * used only if the selected DRM plug-in (agent) supports this sequence of calls. Some DRM
    532      * agents, such as OMA, do not support this utility method, in which case an application must
    533      * invoke {@link #acquireDrmInfo(DrmInfoRequest) acquireDrmInfo()} and
    534      * {@link #processDrmInfo(DrmInfo) processDrmInfo()} separately.
    535      *
    536      * @param drmInfoRequest The {@link DrmInfoRequest} used to acquire the rights.
    537      * @return ERROR_NONE for success; ERROR_UNKNOWN for failure.
    538      */
    539     public int acquireRights(DrmInfoRequest drmInfoRequest) {
    540         DrmInfo drmInfo = acquireDrmInfo(drmInfoRequest);
    541         if (null == drmInfo) {
    542             return ERROR_UNKNOWN;
    543         }
    544         return processDrmInfo(drmInfo);
    545     }
    546 
    547     /**
    548      * Retrieves the type of rights-protected object (for example, content object, rights
    549      * object, and so on) using the specified path or MIME type. At least one parameter must
    550      * be specified to retrieve the DRM object type.
    551      *
    552      * @param path Path to the content or null.
    553      * @param mimeType MIME type of the content or null.
    554      *
    555      * @return An <code>int</code> that corresponds to a {@link DrmStore.DrmObjectType}.
    556      */
    557     public int getDrmObjectType(String path, String mimeType) {
    558         if ((null == path || path.equals("")) && (null == mimeType || mimeType.equals(""))) {
    559             throw new IllegalArgumentException("Path or the mimetype should be non null");
    560         }
    561         return _getDrmObjectType(mUniqueId, path, mimeType);
    562     }
    563 
    564     /**
    565      * Retrieves the type of rights-protected object (for example, content object, rights
    566      * object, and so on) using the specified URI or MIME type. At least one parameter must
    567      * be specified to retrieve the DRM object type.
    568      *
    569      * @param uri URI for the content or null.
    570      * @param mimeType MIME type of the content or null.
    571      *
    572      * @return An <code>int</code> that corresponds to a {@link DrmStore.DrmObjectType}.
    573      */
    574     public int getDrmObjectType(Uri uri, String mimeType) {
    575         if ((null == uri || Uri.EMPTY == uri) && (null == mimeType || mimeType.equals(""))) {
    576             throw new IllegalArgumentException("Uri or the mimetype should be non null");
    577         }
    578         String path = "";
    579         try {
    580             path = convertUriToPath(uri);
    581         } catch (Exception e) {
    582             // Even uri is invalid the mimetype shall be valid, so allow to proceed further.
    583             Log.w(TAG, "Given Uri could not be found in media store");
    584         }
    585         return getDrmObjectType(path, mimeType);
    586     }
    587 
    588     /**
    589      * Retrieves the MIME type embedded in the original content.
    590      *
    591      * @param path Path to the rights-protected content.
    592      *
    593      * @return The MIME type of the original content, such as <code>video/mpeg</code>.
    594      */
    595     public String getOriginalMimeType(String path) {
    596         if (null == path || path.equals("")) {
    597             throw new IllegalArgumentException("Given path should be non null");
    598         }
    599 
    600         String mime = null;
    601 
    602         FileInputStream is = null;
    603         try {
    604             FileDescriptor fd = null;
    605             File file = new File(path);
    606             if (file.exists()) {
    607                 is = new FileInputStream(file);
    608                 fd = is.getFD();
    609             }
    610             mime = _getOriginalMimeType(mUniqueId, path, fd);
    611         } catch (IOException ioe) {
    612         } finally {
    613             if (is != null) {
    614                 try {
    615                     is.close();
    616                 } catch(IOException e) {}
    617             }
    618         }
    619 
    620         return mime;
    621     }
    622 
    623     /**
    624      * Retrieves the MIME type embedded in the original content.
    625      *
    626      * @param uri URI of the rights-protected content.
    627      *
    628      * @return MIME type of the original content, such as <code>video/mpeg</code>.
    629      */
    630     public String getOriginalMimeType(Uri uri) {
    631         if (null == uri || Uri.EMPTY == uri) {
    632             throw new IllegalArgumentException("Given uri is not valid");
    633         }
    634         return getOriginalMimeType(convertUriToPath(uri));
    635     }
    636 
    637     /**
    638      * Checks whether the given content has valid rights.
    639      *
    640      * @param path Path to the rights-protected content.
    641      *
    642      * @return An <code>int</code> representing the {@link DrmStore.RightsStatus} of the content.
    643      */
    644     public int checkRightsStatus(String path) {
    645         return checkRightsStatus(path, DrmStore.Action.DEFAULT);
    646     }
    647 
    648     /**
    649      * Check whether the given content has valid rights.
    650      *
    651      * @param uri URI of the rights-protected content.
    652      *
    653      * @return An <code>int</code> representing the {@link DrmStore.RightsStatus} of the content.
    654      */
    655     public int checkRightsStatus(Uri uri) {
    656         if (null == uri || Uri.EMPTY == uri) {
    657             throw new IllegalArgumentException("Given uri is not valid");
    658         }
    659         return checkRightsStatus(convertUriToPath(uri));
    660     }
    661 
    662     /**
    663      * Checks whether the given rights-protected content has valid rights for the specified
    664      * {@link DrmStore.Action}.
    665      *
    666      * @param path Path to the rights-protected content.
    667      * @param action The {@link DrmStore.Action} to perform.
    668      *
    669      * @return An <code>int</code> representing the {@link DrmStore.RightsStatus} of the content.
    670      */
    671     public int checkRightsStatus(String path, int action) {
    672         if (null == path || path.equals("") || !DrmStore.Action.isValid(action)) {
    673             throw new IllegalArgumentException("Given path or action is not valid");
    674         }
    675         return _checkRightsStatus(mUniqueId, path, action);
    676     }
    677 
    678     /**
    679      * Checks whether the given rights-protected content has valid rights for the specified
    680      * {@link DrmStore.Action}.
    681      *
    682      * @param uri URI for the rights-protected content.
    683      * @param action The {@link DrmStore.Action} to perform.
    684      *
    685      * @return An <code>int</code> representing the {@link DrmStore.RightsStatus} of the content.
    686      */
    687     public int checkRightsStatus(Uri uri, int action) {
    688         if (null == uri || Uri.EMPTY == uri) {
    689             throw new IllegalArgumentException("Given uri is not valid");
    690         }
    691         return checkRightsStatus(convertUriToPath(uri), action);
    692     }
    693 
    694     /**
    695      * Removes the rights associated with the given rights-protected content.
    696      *
    697      * @param path Path to the rights-protected content.
    698      *
    699      * @return ERROR_NONE for success; ERROR_UNKNOWN for failure.
    700      */
    701     public int removeRights(String path) {
    702         if (null == path || path.equals("")) {
    703             throw new IllegalArgumentException("Given path should be non null");
    704         }
    705         return _removeRights(mUniqueId, path);
    706     }
    707 
    708     /**
    709      * Removes the rights associated with the given rights-protected content.
    710      *
    711      * @param uri URI for the rights-protected content.
    712      *
    713      * @return ERROR_NONE for success; ERROR_UNKNOWN for failure.
    714      */
    715     public int removeRights(Uri uri) {
    716         if (null == uri || Uri.EMPTY == uri) {
    717             throw new IllegalArgumentException("Given uri is not valid");
    718         }
    719         return removeRights(convertUriToPath(uri));
    720     }
    721 
    722     /**
    723      * Removes all the rights information of every DRM plug-in (agent) associated with
    724      * the DRM framework. Will be used during a master reset.
    725      *
    726      * @return ERROR_NONE for success; ERROR_UNKNOWN for failure.
    727      */
    728     public int removeAllRights() {
    729         int result = ERROR_UNKNOWN;
    730         if (null != mEventHandler) {
    731             Message msg = mEventHandler.obtainMessage(ACTION_REMOVE_ALL_RIGHTS);
    732             result = (mEventHandler.sendMessage(msg)) ? ERROR_NONE : result;
    733         }
    734         return result;
    735     }
    736 
    737     /**
    738      * Initiates a new conversion session. An application must initiate a conversion session
    739      * with this method each time it downloads a rights-protected file that needs to be converted.
    740      *<p>
    741      * This method applies only to forward-locking (copy protection) DRM schemes.
    742      *
    743      * @param mimeType MIME type of the input data packet.
    744      *
    745      * @return A convert ID that is used used to maintain the conversion session.
    746      */
    747     public int openConvertSession(String mimeType) {
    748         if (null == mimeType || mimeType.equals("")) {
    749             throw new IllegalArgumentException("Path or the mimeType should be non null");
    750         }
    751         return _openConvertSession(mUniqueId, mimeType);
    752     }
    753 
    754     /**
    755      * Converts the input data (content) that is part of a rights-protected file. The converted
    756      * data and status is returned in a {@link DrmConvertedStatus} object. This method should be
    757      * called each time there is a new block of data received by the application.
    758      *
    759      * @param convertId Handle for the conversion session.
    760      * @param inputData Input data that needs to be converted.
    761      *
    762      * @return A {@link DrmConvertedStatus} object that contains the status of the data conversion,
    763      * the converted data, and offset for the header and body signature. An application can
    764      * ignore the offset because it is only relevant to the
    765      * {@link #closeConvertSession closeConvertSession()} method.
    766      */
    767     public DrmConvertedStatus convertData(int convertId, byte[] inputData) {
    768         if (null == inputData || 0 >= inputData.length) {
    769             throw new IllegalArgumentException("Given inputData should be non null");
    770         }
    771         return _convertData(mUniqueId, convertId, inputData);
    772     }
    773 
    774     /**
    775      * Informs the DRM plug-in (agent) that there is no more data to convert or that an error
    776      * has occurred. Upon successful conversion of the data, the DRM agent will provide an offset
    777      * value indicating where the header and body signature should be added. Appending the
    778      * signature is necessary to protect the integrity of the converted file.
    779      *
    780      * @param convertId Handle for the conversion session.
    781      *
    782      * @return A {@link DrmConvertedStatus} object that contains the status of the data conversion,
    783      * the converted data, and the offset for the header and body signature.
    784      */
    785     public DrmConvertedStatus closeConvertSession(int convertId) {
    786         return _closeConvertSession(mUniqueId, convertId);
    787     }
    788 
    789     private int getEventType(int infoType) {
    790         int eventType = -1;
    791 
    792         switch (infoType) {
    793         case DrmInfoRequest.TYPE_REGISTRATION_INFO:
    794         case DrmInfoRequest.TYPE_UNREGISTRATION_INFO:
    795         case DrmInfoRequest.TYPE_RIGHTS_ACQUISITION_INFO:
    796             eventType = DrmEvent.TYPE_DRM_INFO_PROCESSED;
    797             break;
    798         }
    799         return eventType;
    800     }
    801 
    802     private int getErrorType(int infoType) {
    803         int error = -1;
    804 
    805         switch (infoType) {
    806         case DrmInfoRequest.TYPE_REGISTRATION_INFO:
    807         case DrmInfoRequest.TYPE_UNREGISTRATION_INFO:
    808         case DrmInfoRequest.TYPE_RIGHTS_ACQUISITION_INFO:
    809             error = DrmErrorEvent.TYPE_PROCESS_DRM_INFO_FAILED;
    810             break;
    811         }
    812         return error;
    813     }
    814 
    815     /**
    816      * This method expects uri in the following format
    817      *     content://media/<table_name>/<row_index> (or)
    818      *     file://sdcard/test.mp4
    819      *     http://test.com/test.mp4
    820      *
    821      * Here <table_name> shall be "video" or "audio" or "images"
    822      * <row_index> the index of the content in given table
    823      */
    824     private String convertUriToPath(Uri uri) {
    825         String path = null;
    826         if (null != uri) {
    827             String scheme = uri.getScheme();
    828             if (null == scheme || scheme.equals("") ||
    829                     scheme.equals(ContentResolver.SCHEME_FILE)) {
    830                 path = uri.getPath();
    831 
    832             } else if (scheme.equals("http")) {
    833                 path = uri.toString();
    834 
    835             } else if (scheme.equals(ContentResolver.SCHEME_CONTENT)) {
    836                 String[] projection = new String[] {MediaStore.MediaColumns.DATA};
    837                 Cursor cursor = null;
    838                 try {
    839                     cursor = mContext.getContentResolver().query(uri, projection, null,
    840                             null, null);
    841                     if (null == cursor || 0 == cursor.getCount() || !cursor.moveToFirst()) {
    842                         throw new IllegalArgumentException("Given Uri could not be found" +
    843                                 " in media store");
    844                     }
    845                     int pathIndex = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA);
    846                     path = cursor.getString(pathIndex);
    847                 } catch (SQLiteException e) {
    848                     throw new IllegalArgumentException("Given Uri is not formatted in a way " +
    849                             "so that it can be found in media store.");
    850                 } finally {
    851                     if (null != cursor) {
    852                         cursor.close();
    853                     }
    854                 }
    855             } else {
    856                 throw new IllegalArgumentException("Given Uri scheme is not supported");
    857             }
    858         }
    859         return path;
    860     }
    861 
    862     // private native interfaces
    863     private native int _initialize();
    864 
    865     private native void _setListeners(int uniqueId, Object weak_this);
    866 
    867     private native void _release(int uniqueId);
    868 
    869     private native void _installDrmEngine(int uniqueId, String engineFilepath);
    870 
    871     private native ContentValues _getConstraints(int uniqueId, String path, int usage);
    872 
    873     private native ContentValues _getMetadata(int uniqueId, String path);
    874 
    875     private native boolean _canHandle(int uniqueId, String path, String mimeType);
    876 
    877     private native DrmInfoStatus _processDrmInfo(int uniqueId, DrmInfo drmInfo);
    878 
    879     private native DrmInfo _acquireDrmInfo(int uniqueId, DrmInfoRequest drmInfoRequest);
    880 
    881     private native int _saveRights(
    882             int uniqueId, DrmRights drmRights, String rightsPath, String contentPath);
    883 
    884     private native int _getDrmObjectType(int uniqueId, String path, String mimeType);
    885 
    886     private native String _getOriginalMimeType(int uniqueId, String path, FileDescriptor fd);
    887 
    888     private native int _checkRightsStatus(int uniqueId, String path, int action);
    889 
    890     private native int _removeRights(int uniqueId, String path);
    891 
    892     private native int _removeAllRights(int uniqueId);
    893 
    894     private native int _openConvertSession(int uniqueId, String mimeType);
    895 
    896     private native DrmConvertedStatus _convertData(
    897             int uniqueId, int convertId, byte[] inputData);
    898 
    899     private native DrmConvertedStatus _closeConvertSession(int uniqueId, int convertId);
    900 
    901     private native DrmSupportInfo[] _getAllSupportInfo(int uniqueId);
    902 
    903     private void createEventThreads() {
    904         if (mEventHandler == null && mInfoHandler == null) {
    905             mInfoThread = new HandlerThread("DrmManagerClient.InfoHandler");
    906             mInfoThread.start();
    907             mInfoHandler = new InfoHandler(mInfoThread.getLooper());
    908 
    909             mEventThread = new HandlerThread("DrmManagerClient.EventHandler");
    910             mEventThread.start();
    911             mEventHandler = new EventHandler(mEventThread.getLooper());
    912         }
    913     }
    914 
    915     private void createListeners() {
    916         _setListeners(mUniqueId, new WeakReference<DrmManagerClient>(this));
    917     }
    918 }
    919 
    920