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