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