MediaModel.java revision 8eed706474910ccb978acda03e85d3261037da6e
1/*
2 * Copyright (C) 2008 Esmertec AG.
3 * Copyright (C) 2008 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18package com.android.mms.model;
19
20import com.android.mms.R;
21import com.android.mms.drm.DrmUtils;
22import com.android.mms.drm.DrmWrapper;
23import com.google.android.mms.MmsException;
24
25import org.w3c.dom.events.EventListener;
26
27import android.content.ContentResolver;
28import android.content.Context;
29import android.drm.mobile1.DrmException;
30import android.media.MediaPlayer;
31import android.net.Uri;
32import android.util.Log;
33
34import java.io.FileInputStream;
35import java.io.IOException;
36import java.io.InputStream;
37import java.util.ArrayList;
38
39public abstract class MediaModel extends Model implements EventListener {
40    private static final String TAG = "MediaModel";
41
42    protected Context mContext;
43    protected int mBegin;
44    protected int mDuration;
45    protected String mTag;
46    protected String mSrc;
47    protected String mContentType;
48    private Uri mUri;
49    private byte[] mData;
50    protected short mFill;
51    protected int mSize;
52    protected int mSeekTo;
53    protected DrmWrapper mDrmObjectWrapper;
54
55    private final ArrayList<MediaAction> mMediaActions;
56    public static enum MediaAction {
57        NO_ACTIVE_ACTION,
58        START,
59        STOP,
60        PAUSE,
61        SEEK,
62    }
63
64    public MediaModel(Context context, String tag, Uri uri) {
65        this(context, tag, null, null, uri);
66    }
67
68    public MediaModel(Context context, String tag, String contentType,
69            String src, Uri uri) {
70        mContext = context;
71        mTag = tag;
72        mContentType = contentType;
73        mSrc = src;
74        mUri = uri;
75        initMediaSize();
76        mMediaActions = new ArrayList<MediaAction>();
77    }
78
79    public MediaModel(Context context, String tag, String contentType,
80            String src, byte[] data) {
81        if (data == null) {
82            throw new IllegalArgumentException("data may not be null.");
83        }
84
85        mContext = context;
86        mTag = tag;
87        mContentType = contentType;
88        mSrc = src;
89        mData = data;
90        mSize = data.length;
91        mMediaActions = new ArrayList<MediaAction>();
92    }
93
94    public MediaModel(Context context, String tag, String contentType,
95            String src, DrmWrapper wrapper) throws IOException {
96        mContext = context;
97        mTag = tag;
98        mContentType = contentType;
99        mSrc = src;
100        mDrmObjectWrapper = wrapper;
101        mUri = DrmUtils.insert(context, wrapper);
102        mSize = wrapper.getOriginalData().length;
103        mMediaActions = new ArrayList<MediaAction>();
104    }
105
106    public int getBegin() {
107        return mBegin;
108    }
109
110    public void setBegin(int begin) {
111        mBegin = begin;
112        notifyModelChanged(true);
113    }
114
115    public int getDuration() {
116        return mDuration;
117    }
118
119    public void setDuration(int duration) {
120        if (isPlayable() && (duration < 0)) {
121            // 'indefinite' duration, we should try to find its exact value;
122            try {
123                initMediaDuration();
124            } catch (MmsException e) {
125                // On error, keep default duration.
126                Log.e(TAG, e.getMessage(), e);
127                return;
128            }
129        } else {
130            mDuration = duration;
131        }
132        notifyModelChanged(true);
133    }
134
135    public String getTag() {
136        return mTag;
137    }
138
139    public String getContentType() {
140        return mContentType;
141    }
142
143    /**
144     * Get the URI of the media without checking DRM rights. Use this method
145     * only if the media is NOT DRM protected.
146     *
147     * @return The URI of the media.
148     */
149    public Uri getUri() {
150        return mUri;
151    }
152
153    /**
154     * Get the URI of the media with checking DRM rights. Use this method
155     * if the media is probably DRM protected.
156     *
157     * @return The URI of the media.
158     * @throws DrmException Insufficient DRM rights detected.
159     */
160    public Uri getUriWithDrmCheck() throws DrmException {
161        if (mUri != null) {
162            if (isDrmProtected() && !mDrmObjectWrapper.consumeRights()) {
163                throw new DrmException("Insufficient DRM rights.");
164            }
165        }
166        return mUri;
167    }
168
169    public byte[] getData() throws DrmException {
170        if (mData != null) {
171            if (isDrmProtected() && !mDrmObjectWrapper.consumeRights()) {
172                throw new DrmException(
173                        mContext.getString(R.string.insufficient_drm_rights));
174            }
175
176            byte[] data = new byte[mData.length];
177            System.arraycopy(mData, 0, data, 0, mData.length);
178            return data;
179        }
180        return null;
181    }
182
183    /**
184     * @param uri the mUri to set
185     */
186    void setUri(Uri uri) {
187        mUri = uri;
188    }
189
190    /**
191     * @return the mSrc
192     */
193    public String getSrc() {
194        return mSrc;
195    }
196
197    /**
198     * @return the mFill
199     */
200    public short getFill() {
201        return mFill;
202    }
203
204    /**
205     * @param fill the mFill to set
206     */
207    public void setFill(short fill) {
208        mFill = fill;
209        notifyModelChanged(true);
210    }
211
212    public int getMediaSize() {
213        return mSize;
214    }
215
216    public boolean isText() {
217        return mTag.equals(SmilHelper.ELEMENT_TAG_TEXT);
218    }
219
220    public boolean isImage() {
221        return mTag.equals(SmilHelper.ELEMENT_TAG_IMAGE);
222    }
223
224    public boolean isVideo() {
225        return mTag.equals(SmilHelper.ELEMENT_TAG_VIDEO);
226    }
227
228    public boolean isAudio() {
229        return mTag.equals(SmilHelper.ELEMENT_TAG_AUDIO);
230    }
231
232    public boolean isDrmProtected() {
233        return mDrmObjectWrapper != null;
234    }
235
236    public boolean isAllowedToForward() {
237        return mDrmObjectWrapper.isAllowedToForward();
238    }
239
240    protected void initMediaDuration() throws MmsException {
241        if (mUri == null) {
242            throw new IllegalArgumentException("Uri may not be null.");
243        }
244
245        MediaPlayer mediaPlayer = new MediaPlayer();
246        try {
247            mediaPlayer.setDataSource(mContext, mUri);
248            mediaPlayer.prepare();
249            mDuration = mediaPlayer.getDuration();
250        } catch (IOException e) {
251            Log.e(TAG, "Unexpected IOException.", e);
252            throw new MmsException(e);
253        } finally {
254            mediaPlayer.release();
255        }
256    }
257
258    private void initMediaSize() {
259        ContentResolver cr = mContext.getContentResolver();
260        InputStream input = null;
261        try {
262            input = cr.openInputStream(mUri);
263            if (input instanceof FileInputStream) {
264                // avoid reading the whole stream to get its length
265                FileInputStream f = (FileInputStream) input;
266                mSize = (int) f.getChannel().size();
267            } else {
268                while (-1 != input.read()) {
269                    mSize++;
270                }
271            }
272        } catch (IOException e) {
273            // Ignore
274            Log.e(TAG, "IOException caught while opening or reading stream", e);
275        } finally {
276            if (null != input) {
277                try {
278                    input.close();
279                } catch (IOException e) {
280                    // Ignore
281                    Log.e(TAG, "IOException caught while closing stream", e);
282                }
283            }
284        }
285    }
286
287    public static boolean isMmsUri(Uri uri) {
288        return uri.getAuthority().startsWith("mms");
289    }
290
291    public int getSeekTo() {
292        return mSeekTo;
293    }
294
295    public void appendAction(MediaAction action) {
296        mMediaActions.add(action);
297    }
298
299    public MediaAction getCurrentAction() {
300        if (0 == mMediaActions.size()) {
301            return MediaAction.NO_ACTIVE_ACTION;
302        }
303        return mMediaActions.remove(0);
304    }
305
306    protected boolean isPlayable() {
307        return false;
308    }
309
310    public DrmWrapper getDrmObject() {
311        return mDrmObjectWrapper;
312    }
313}
314