Home | History | Annotate | Download | only in model
      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 org.w3c.dom.events.Event;
     21 import org.w3c.dom.smil.ElementTime;
     22 
     23 import android.content.ContentResolver;
     24 import android.content.Context;
     25 import android.database.Cursor;
     26 import android.database.sqlite.SqliteWrapper;
     27 import android.net.Uri;
     28 import android.provider.MediaStore.Images;
     29 import android.text.TextUtils;
     30 import android.util.Log;
     31 import android.webkit.MimeTypeMap;
     32 
     33 import com.android.mms.ContentRestrictionException;
     34 import com.android.mms.LogTag;
     35 import com.android.mms.MmsApp;
     36 import com.android.mms.dom.events.EventImpl;
     37 import com.android.mms.dom.smil.SmilMediaElementImpl;
     38 import com.android.mms.util.ItemLoadedCallback;
     39 import com.android.mms.util.ItemLoadedFuture;
     40 import com.android.mms.util.ThumbnailManager;
     41 import com.google.android.mms.ContentType;
     42 import com.google.android.mms.MmsException;
     43 
     44 public class VideoModel extends RegionMediaModel {
     45     private static final String TAG = MediaModel.TAG;
     46     private static final boolean DEBUG = true;
     47     private static final boolean LOCAL_LOGV = false;
     48     private ItemLoadedFuture mItemLoadedFuture;
     49 
     50     public VideoModel(Context context, Uri uri, RegionModel region)
     51             throws MmsException {
     52         this(context, null, null, uri, region);
     53         initModelFromUri(uri);
     54         checkContentRestriction();
     55     }
     56 
     57     public VideoModel(Context context, String contentType, String src,
     58             Uri uri, RegionModel region) throws MmsException {
     59         super(context, SmilHelper.ELEMENT_TAG_VIDEO, contentType, src, uri, region);
     60     }
     61 
     62     private void initModelFromUri(Uri uri) throws MmsException {
     63         String scheme = uri.getScheme();
     64         if (scheme.equals("content")) {
     65             initFromContentUri(uri);
     66         } else if (uri.getScheme().equals("file")) {
     67             initFromFile(uri);
     68         }
     69         initMediaDuration();
     70     }
     71 
     72     private void initFromFile(Uri uri) {
     73         String path = uri.getPath();
     74         mSrc = path.substring(path.lastIndexOf('/') + 1);
     75         MimeTypeMap mimeTypeMap = MimeTypeMap.getSingleton();
     76         String extension = MimeTypeMap.getFileExtensionFromUrl(mSrc);
     77         if (TextUtils.isEmpty(extension)) {
     78             // getMimeTypeFromExtension() doesn't handle spaces in filenames nor can it handle
     79             // urlEncoded strings. Let's try one last time at finding the extension.
     80             int dotPos = mSrc.lastIndexOf('.');
     81             if (0 <= dotPos) {
     82                 extension = mSrc.substring(dotPos + 1);
     83             }
     84         }
     85         mContentType = mimeTypeMap.getMimeTypeFromExtension(extension);
     86         // It's ok if mContentType is null. Eventually we'll show a toast telling the
     87         // user the video couldn't be attached.
     88 
     89         if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) {
     90             Log.v(TAG, "New VideoModel initFromFile created:"
     91                     + " mSrc=" + mSrc
     92                     + " mContentType=" + mContentType
     93                     + " mUri=" + uri);
     94         }
     95     }
     96 
     97     private void initFromContentUri(Uri uri) throws MmsException {
     98         ContentResolver cr = mContext.getContentResolver();
     99         Cursor c = SqliteWrapper.query(mContext, cr, uri, null, null, null, null);
    100 
    101         if (c != null) {
    102             try {
    103                 if (c.moveToFirst()) {
    104                     String path;
    105                     try {
    106                         // Local videos will have a data column
    107                         path = c.getString(c.getColumnIndexOrThrow(Images.Media.DATA));
    108                     } catch (IllegalArgumentException e) {
    109                         // For non-local videos, the path is the uri
    110                         path = uri.toString();
    111                     }
    112                     mSrc = path.substring(path.lastIndexOf('/') + 1);
    113                     mContentType = c.getString(c.getColumnIndexOrThrow(
    114                             Images.Media.MIME_TYPE));
    115                     if (TextUtils.isEmpty(mContentType)) {
    116                         throw new MmsException("Type of media is unknown.");
    117                     }
    118 
    119                     if (mContentType.equals(ContentType.VIDEO_MP4) && !(TextUtils.isEmpty(mSrc))) {
    120                         int index = mSrc.lastIndexOf(".");
    121                         if (index != -1) {
    122                             try {
    123                                 String extension = mSrc.substring(index + 1);
    124                                 if (!(TextUtils.isEmpty(extension)) &&
    125                                         (extension.equalsIgnoreCase("3gp") ||
    126                                         extension.equalsIgnoreCase("3gpp") ||
    127                                         extension.equalsIgnoreCase("3g2"))) {
    128                                     mContentType = ContentType.VIDEO_3GPP;
    129                                 }
    130                             } catch(IndexOutOfBoundsException ex) {
    131                                 if (LOCAL_LOGV) {
    132                                     Log.v(TAG, "Media extension is unknown.");
    133                                 }
    134                             }
    135                         }
    136                     }
    137 
    138                     if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) {
    139                         Log.v(TAG, "New VideoModel initFromContentUri created:"
    140                                 + " mSrc=" + mSrc
    141                                 + " mContentType=" + mContentType
    142                                 + " mUri=" + uri);
    143                     }
    144                 } else {
    145                     throw new MmsException("Nothing found: " + uri);
    146                 }
    147             } finally {
    148                 c.close();
    149             }
    150         } else {
    151             throw new MmsException("Bad URI: " + uri);
    152         }
    153     }
    154 
    155     // EventListener Interface
    156     public void handleEvent(Event evt) {
    157         String evtType = evt.getType();
    158         if (LOCAL_LOGV || Log.isLoggable(LogTag.APP, Log.VERBOSE)) {
    159             Log.v(TAG, "[VideoModel] handleEvent " + evt.getType() + " on " + this);
    160         }
    161 
    162         MediaAction action = MediaAction.NO_ACTIVE_ACTION;
    163         if (evtType.equals(SmilMediaElementImpl.SMIL_MEDIA_START_EVENT)) {
    164             action = MediaAction.START;
    165 
    166             // if the Music player app is playing audio, we should pause that so it won't
    167             // interfere with us playing video here.
    168             pauseMusicPlayer();
    169 
    170             mVisible = true;
    171         } else if (evtType.equals(SmilMediaElementImpl.SMIL_MEDIA_END_EVENT)) {
    172             action = MediaAction.STOP;
    173             if (mFill != ElementTime.FILL_FREEZE) {
    174                 mVisible = false;
    175             }
    176         } else if (evtType.equals(SmilMediaElementImpl.SMIL_MEDIA_PAUSE_EVENT)) {
    177             action = MediaAction.PAUSE;
    178             mVisible = true;
    179         } else if (evtType.equals(SmilMediaElementImpl.SMIL_MEDIA_SEEK_EVENT)) {
    180             action = MediaAction.SEEK;
    181             mSeekTo = ((EventImpl) evt).getSeekTo();
    182             mVisible = true;
    183         }
    184 
    185         appendAction(action);
    186         notifyModelChanged(false);
    187     }
    188 
    189     protected void checkContentRestriction() throws ContentRestrictionException {
    190         ContentRestriction cr = ContentRestrictionFactory.getContentRestriction();
    191         cr.checkVideoContentType(mContentType);
    192     }
    193 
    194     @Override
    195     protected boolean isPlayable() {
    196         return true;
    197     }
    198 
    199     public ItemLoadedFuture loadThumbnailBitmap(ItemLoadedCallback callback) {
    200         ThumbnailManager thumbnailManager = MmsApp.getApplication().getThumbnailManager();
    201         mItemLoadedFuture = thumbnailManager.getVideoThumbnail(getUri(), callback);
    202         return mItemLoadedFuture;
    203     }
    204 
    205     public void cancelThumbnailLoading() {
    206         if (mItemLoadedFuture != null && !mItemLoadedFuture.isDone()) {
    207             if (Log.isLoggable(LogTag.APP, Log.DEBUG)) {
    208                 Log.v(TAG, "cancelThumbnailLoading for: " + this);
    209             }
    210             mItemLoadedFuture.cancel(getUri());
    211             mItemLoadedFuture = null;
    212         }
    213     }
    214 }
    215