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