• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
18 package com.android.mms.model;
19 
20 import com.android.mms.R;
21 import com.android.mms.LogTag;
22 import android.drm.mobile1.DrmException;
23 import com.android.mms.drm.DrmWrapper;
24 import android.media.MediaMetadataRetriever;        // TODO: remove dependency for SDK build
25 import com.google.android.mms.MmsException;
26 import com.android.mms.drm.DrmUtils;
27 
28 import org.w3c.dom.events.EventListener;
29 
30 import android.content.ContentResolver;
31 import android.content.Context;
32 import android.content.Intent;
33 import android.net.Uri;
34 import android.util.Log;
35 
36 import java.io.FileInputStream;
37 import java.io.FileNotFoundException;
38 import java.io.IOException;
39 import java.io.InputStream;
40 import java.util.ArrayList;
41 
42 public abstract class MediaModel extends Model implements EventListener {
43     protected static final String TAG = "Mms/media";
44 
45     private final static String MUSIC_SERVICE_ACTION = "com.android.music.musicservicecommand";
46 
47     protected Context mContext;
48     protected int mBegin;
49     protected int mDuration;
50     protected String mTag;
51     protected String mSrc;
52     protected String mContentType;
53     private Uri mUri;
54     private byte[] mData;
55     protected short mFill;
56     protected int mSize;
57     protected int mSeekTo;
58     protected DrmWrapper mDrmObjectWrapper;
59     protected boolean mMediaResizeable;
60 
61     private final ArrayList<MediaAction> mMediaActions;
62     public static enum MediaAction {
63         NO_ACTIVE_ACTION,
64         START,
65         STOP,
66         PAUSE,
67         SEEK,
68     }
69 
MediaModel(Context context, String tag, String contentType, String src, Uri uri)70     public MediaModel(Context context, String tag, String contentType,
71             String src, Uri uri) throws MmsException {
72         mContext = context;
73         mTag = tag;
74         mContentType = contentType;
75         mSrc = src;
76         mUri = uri;
77         initMediaSize();
78         mMediaActions = new ArrayList<MediaAction>();
79     }
80 
MediaModel(Context context, String tag, String contentType, String src, byte[] data)81     public MediaModel(Context context, String tag, String contentType,
82             String src, byte[] data) {
83         if (data == null) {
84             throw new IllegalArgumentException("data may not be null.");
85         }
86 
87         mContext = context;
88         mTag = tag;
89         mContentType = contentType;
90         mSrc = src;
91         mData = data;
92         mSize = data.length;
93         mMediaActions = new ArrayList<MediaAction>();
94     }
95 
MediaModel(Context context, String tag, String contentType, String src, DrmWrapper wrapper)96     public MediaModel(Context context, String tag, String contentType,
97             String src, DrmWrapper wrapper) throws IOException {
98         mContext = context;
99         mTag = tag;
100         mContentType = contentType;
101         mSrc = src;
102         mDrmObjectWrapper = wrapper;
103         mUri = DrmUtils.insert(context, wrapper);
104         mSize = wrapper.getOriginalData().length;
105         mMediaActions = new ArrayList<MediaAction>();
106     }
107 
getBegin()108     public int getBegin() {
109         return mBegin;
110     }
111 
setBegin(int begin)112     public void setBegin(int begin) {
113         mBegin = begin;
114         notifyModelChanged(true);
115     }
116 
getDuration()117     public int getDuration() {
118         return mDuration;
119     }
120 
setDuration(int duration)121     public void setDuration(int duration) {
122         if (isPlayable() && (duration < 0)) {
123             // 'indefinite' duration, we should try to find its exact value;
124             try {
125                 initMediaDuration();
126             } catch (MmsException e) {
127                 // On error, keep default duration.
128                 Log.e(TAG, e.getMessage(), e);
129                 return;
130             }
131         } else {
132             mDuration = duration;
133         }
134         notifyModelChanged(true);
135     }
136 
getTag()137     public String getTag() {
138         return mTag;
139     }
140 
getContentType()141     public String getContentType() {
142         return mContentType;
143     }
144 
145     /**
146      * Get the URI of the media without checking DRM rights. Use this method
147      * only if the media is NOT DRM protected.
148      *
149      * @return The URI of the media.
150      */
getUri()151     public Uri getUri() {
152         return mUri;
153     }
154 
155     /**
156      * Get the URI of the media with checking DRM rights. Use this method
157      * if the media is probably DRM protected.
158      *
159      * @return The URI of the media.
160      * @throws DrmException Insufficient DRM rights detected.
161      */
getUriWithDrmCheck()162     public Uri getUriWithDrmCheck() throws DrmException {
163         if (mUri != null) {
164             if (isDrmProtected() && !mDrmObjectWrapper.consumeRights()) {
165                 throw new DrmException("Insufficient DRM rights.");
166             }
167         }
168         return mUri;
169     }
170 
getData()171     public byte[] getData() throws DrmException {
172         if (mData != null) {
173             if (isDrmProtected() && !mDrmObjectWrapper.consumeRights()) {
174                 throw new DrmException(
175                         mContext.getString(R.string.insufficient_drm_rights));
176             }
177 
178             byte[] data = new byte[mData.length];
179             System.arraycopy(mData, 0, data, 0, mData.length);
180             return data;
181         }
182         return null;
183     }
184 
185     /**
186      * @param uri the mUri to set
187      */
setUri(Uri uri)188     void setUri(Uri uri) {
189         mUri = uri;
190     }
191 
192     /**
193      * @return the mSrc
194      */
getSrc()195     public String getSrc() {
196         return mSrc;
197     }
198 
199     /**
200      * @return the mFill
201      */
getFill()202     public short getFill() {
203         return mFill;
204     }
205 
206     /**
207      * @param fill the mFill to set
208      */
setFill(short fill)209     public void setFill(short fill) {
210         mFill = fill;
211         notifyModelChanged(true);
212     }
213 
214     /**
215      * @return whether the media is resizable or not. For instance, a picture can be resized
216      * to smaller dimensions or lower resolution. Other media, such as video and sounds, aren't
217      * currently able to be resized.
218      */
getMediaResizable()219     public boolean getMediaResizable() {
220         return mMediaResizeable;
221     }
222 
223     /**
224      * @return the size of the attached media
225      */
getMediaSize()226     public int getMediaSize() {
227         return mSize;
228     }
229 
isText()230     public boolean isText() {
231         return mTag.equals(SmilHelper.ELEMENT_TAG_TEXT);
232     }
233 
isImage()234     public boolean isImage() {
235         return mTag.equals(SmilHelper.ELEMENT_TAG_IMAGE);
236     }
237 
isVideo()238     public boolean isVideo() {
239         return mTag.equals(SmilHelper.ELEMENT_TAG_VIDEO);
240     }
241 
isAudio()242     public boolean isAudio() {
243         return mTag.equals(SmilHelper.ELEMENT_TAG_AUDIO);
244     }
245 
isDrmProtected()246     public boolean isDrmProtected() {
247         return mDrmObjectWrapper != null;
248     }
249 
isAllowedToForward()250     public boolean isAllowedToForward() {
251         return mDrmObjectWrapper.isAllowedToForward();
252     }
253 
initMediaDuration()254     protected void initMediaDuration() throws MmsException {
255         if (mUri == null) {
256             throw new IllegalArgumentException("Uri may not be null.");
257         }
258 
259         MediaMetadataRetriever retriever = new MediaMetadataRetriever();
260         int duration = 0;
261         try {
262             retriever.setDataSource(mContext, mUri);
263             String dur = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
264             if (dur != null) {
265                 duration = Integer.parseInt(dur);
266             }
267             mDuration = duration;
268         } catch (Exception ex) {
269             Log.e(TAG, "MediaMetadataRetriever failed to get duration for " + mUri.getPath(), ex);
270             throw new MmsException(ex);
271         } finally {
272             retriever.release();
273         }
274     }
275 
initMediaSize()276     private void initMediaSize() throws MmsException {
277         ContentResolver cr = mContext.getContentResolver();
278         InputStream input = null;
279         try {
280             input = cr.openInputStream(mUri);
281             if (input instanceof FileInputStream) {
282                 // avoid reading the whole stream to get its length
283                 FileInputStream f = (FileInputStream) input;
284                 mSize = (int) f.getChannel().size();
285             } else {
286                 while (-1 != input.read()) {
287                     mSize++;
288                 }
289             }
290 
291         } catch (IOException e) {
292             // Ignore
293             Log.e(TAG, "IOException caught while opening or reading stream", e);
294             if (e instanceof FileNotFoundException) {
295                 throw new MmsException(e.getMessage());
296             }
297         } finally {
298             if (null != input) {
299                 try {
300                     input.close();
301                 } catch (IOException e) {
302                     // Ignore
303                     Log.e(TAG, "IOException caught while closing stream", e);
304                 }
305             }
306         }
307     }
308 
isMmsUri(Uri uri)309     public static boolean isMmsUri(Uri uri) {
310         return uri.getAuthority().startsWith("mms");
311     }
312 
getSeekTo()313     public int getSeekTo() {
314         return mSeekTo;
315     }
316 
appendAction(MediaAction action)317     public void appendAction(MediaAction action) {
318         mMediaActions.add(action);
319     }
320 
getCurrentAction()321     public MediaAction getCurrentAction() {
322         if (0 == mMediaActions.size()) {
323             return MediaAction.NO_ACTIVE_ACTION;
324         }
325         return mMediaActions.remove(0);
326     }
327 
isPlayable()328     protected boolean isPlayable() {
329         return false;
330     }
331 
getDrmObject()332     public DrmWrapper getDrmObject() {
333         return mDrmObjectWrapper;
334     }
335 
pauseMusicPlayer()336     protected void pauseMusicPlayer() {
337         if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) {
338             Log.d(TAG, "pauseMusicPlayer");
339         }
340 
341         Intent i = new Intent(MUSIC_SERVICE_ACTION);
342         i.putExtra("command", "pause");
343         mContext.sendBroadcast(i);
344     }
345 
346     /**
347      * If the attached media is resizeable, resize it to fit within the byteLimit. Save the
348      * new part in the pdu.
349      * @param byteLimit the max size of the media attachment
350      * @throws MmsException
351      */
resizeMedia(int byteLimit, long messageId)352     protected void resizeMedia(int byteLimit, long messageId) throws MmsException {
353     }
354 }
355