10a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang/*
20a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang * Copyright (C) 2011 The Android Open Source Project
30a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang *
40a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang * Licensed under the Apache License, Version 2.0 (the "License");
50a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang * you may not use this file except in compliance with the License.
60a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang * You may obtain a copy of the License at
70a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang *
80a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang *      http://www.apache.org/licenses/LICENSE-2.0
90a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang *
100a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang * Unless required by applicable law or agreed to in writing, software
110a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang * distributed under the License is distributed on an "AS IS" BASIS,
120a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang * See the License for the specific language governing permissions and
140a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang * limitations under the License.
150a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang *
160a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang */
170a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wangpackage com.android.providers.downloads;
180a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang
190a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wangimport android.content.Context;
200a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wangimport android.drm.DrmConvertedStatus;
210a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wangimport android.drm.DrmManagerClient;
220a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wangimport android.util.Log;
230a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wangimport android.provider.Downloads;
240a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang
250a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wangimport java.io.FileNotFoundException;
260a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wangimport java.io.IOException;
270a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wangimport java.io.RandomAccessFile;
280a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang
290a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang
300a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wangpublic class DrmConvertSession {
310a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang    private DrmManagerClient mDrmClient;
320a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang    private int mConvertSessionId;
330a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang
340a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang    private DrmConvertSession(DrmManagerClient drmClient, int convertSessionId) {
350a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang        mDrmClient = drmClient;
360a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang        mConvertSessionId = convertSessionId;
370a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang    }
380a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang
390a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang    /**
400a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang     * Start of converting a file.
410a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang     *
420a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang     * @param context The context of the application running the convert session.
430a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang     * @param mimeType Mimetype of content that shall be converted.
440a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang     * @return A convert session or null in case an error occurs.
450a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang     */
460a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang    public static DrmConvertSession open(Context context, String mimeType) {
470a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang        DrmManagerClient drmClient = null;
480a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang        int convertSessionId = -1;
490a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang        if (context != null && mimeType != null && !mimeType.equals("")) {
500a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang            try {
510a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                drmClient = new DrmManagerClient(context);
520a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                try {
530a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                    convertSessionId = drmClient.openConvertSession(mimeType);
540a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                } catch (IllegalArgumentException e) {
550a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                    Log.w(Constants.TAG, "Conversion of Mimetype: " + mimeType
560a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                            + " is not supported.", e);
570a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                } catch (IllegalStateException e) {
580a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                    Log.w(Constants.TAG, "Could not access Open DrmFramework.", e);
590a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                }
600a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang            } catch (IllegalArgumentException e) {
610a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                Log.w(Constants.TAG,
620a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                        "DrmManagerClient instance could not be created, context is Illegal.");
630a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang            } catch (IllegalStateException e) {
640a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                Log.w(Constants.TAG, "DrmManagerClient didn't initialize properly.");
650a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang            }
660a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang        }
670a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang
680a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang        if (drmClient == null || convertSessionId < 0) {
690a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang            return null;
700a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang        } else {
710a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang            return new DrmConvertSession(drmClient, convertSessionId);
720a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang        }
730a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang    }
740a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang    /**
750a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang     * Convert a buffer of data to protected format.
760a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang     *
770a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang     * @param buffer Buffer filled with data to convert.
780a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang     * @param size The number of bytes that shall be converted.
790a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang     * @return A Buffer filled with converted data, if execution is ok, in all
800a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang     *         other case null.
810a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang     */
820a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang    public byte [] convert(byte[] inBuffer, int size) {
830a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang        byte[] result = null;
840a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang        if (inBuffer != null) {
850a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang            DrmConvertedStatus convertedStatus = null;
860a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang            try {
870a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                if (size != inBuffer.length) {
880a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                    byte[] buf = new byte[size];
890a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                    System.arraycopy(inBuffer, 0, buf, 0, size);
900a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                    convertedStatus = mDrmClient.convertData(mConvertSessionId, buf);
910a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                } else {
920a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                    convertedStatus = mDrmClient.convertData(mConvertSessionId, inBuffer);
930a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                }
940a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang
950a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                if (convertedStatus != null &&
960a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                        convertedStatus.statusCode == DrmConvertedStatus.STATUS_OK &&
970a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                        convertedStatus.convertedData != null) {
980a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                    result = convertedStatus.convertedData;
990a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                }
1000a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang            } catch (IllegalArgumentException e) {
1010a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                Log.w(Constants.TAG, "Buffer with data to convert is illegal. Convertsession: "
1020a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                        + mConvertSessionId, e);
1030a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang            } catch (IllegalStateException e) {
1040a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                Log.w(Constants.TAG, "Could not convert data. Convertsession: " +
1050a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                        mConvertSessionId, e);
1060a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang            }
1070a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang        } else {
1080a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang            throw new IllegalArgumentException("Parameter inBuffer is null");
1090a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang        }
1100a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang        return result;
1110a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang    }
1120a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang
1130a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang    /**
1140a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang     * Ends a conversion session of a file.
1150a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang     *
1160a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang     * @param fileName The filename of the converted file.
1170a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang     * @return Downloads.Impl.STATUS_SUCCESS if execution is ok.
1180a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang     *         Downloads.Impl.STATUS_FILE_ERROR in case converted file can not
1190a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang     *         be accessed. Downloads.Impl.STATUS_NOT_ACCEPTABLE if a problem
1200a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang     *         occurs when accessing drm framework.
1210a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang     *         Downloads.Impl.STATUS_UNKNOWN_ERROR if a general error occurred.
1220a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang     */
1230a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang    public int close(String filename) {
1240a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang        DrmConvertedStatus convertedStatus = null;
1250a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang        int result = Downloads.Impl.STATUS_UNKNOWN_ERROR;
1260a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang        if (mDrmClient != null && mConvertSessionId >= 0) {
1270a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang            try {
1280a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                convertedStatus = mDrmClient.closeConvertSession(mConvertSessionId);
1290a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                if (convertedStatus == null ||
1300a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                        convertedStatus.statusCode != DrmConvertedStatus.STATUS_OK ||
1310a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                        convertedStatus.convertedData == null) {
1320a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                    result = Downloads.Impl.STATUS_NOT_ACCEPTABLE;
1330a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                } else {
1340a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                    RandomAccessFile rndAccessFile = null;
1350a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                    try {
1360a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                        rndAccessFile = new RandomAccessFile(filename, "rw");
1370a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                        rndAccessFile.seek(convertedStatus.offset);
1380a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                        rndAccessFile.write(convertedStatus.convertedData);
1390a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                        result = Downloads.Impl.STATUS_SUCCESS;
1400a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                    } catch (FileNotFoundException e) {
1410a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                        result = Downloads.Impl.STATUS_FILE_ERROR;
1420a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                        Log.w(Constants.TAG, "File: " + filename + " could not be found.", e);
1430a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                    } catch (IOException e) {
1440a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                        result = Downloads.Impl.STATUS_FILE_ERROR;
1450a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                        Log.w(Constants.TAG, "Could not access File: " + filename + " .", e);
1460a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                    } catch (IllegalArgumentException e) {
1470a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                        result = Downloads.Impl.STATUS_FILE_ERROR;
1480a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                        Log.w(Constants.TAG, "Could not open file in mode: rw", e);
1490a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                    } catch (SecurityException e) {
1500a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                        Log.w(Constants.TAG, "Access to File: " + filename +
1510a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                                " was denied denied by SecurityManager.", e);
1520a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                    } finally {
1530a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                        if (rndAccessFile != null) {
1540a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                            try {
1550a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                                rndAccessFile.close();
1560a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                            } catch (IOException e) {
1570a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                                result = Downloads.Impl.STATUS_FILE_ERROR;
1580a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                                Log.w(Constants.TAG, "Failed to close File:" + filename
1590a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                                        + ".", e);
1600a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                            }
1610a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                        }
1620a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                    }
1630a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                }
1640a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang            } catch (IllegalStateException e) {
1650a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                Log.w(Constants.TAG, "Could not close convertsession. Convertsession: " +
1660a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang                        mConvertSessionId, e);
1670a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang            }
1680a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang        }
1690a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang        return result;
1700a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang    }
1710a17c2a28738d6ecb274def0e8e54f556d89f5f3Gloria Wang}
172