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