Android Open Source - Locast-Core-Android Cast Media






From Project

Back to project page Locast-Core-Android.

License

The source code is released under:

GNU General Public License

If you think the Android project Locast-Core-Android listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package edu.mit.mobile.android.locast.data;
/* w  ww.  j  av a 2 s  .co m*/
/*
 * Copyright (C) 2011-2013  MIT Mobile Experience Lab
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

import java.io.File;
import java.io.IOException;
import java.net.URLConnection;

import org.json.JSONException;
import org.json.JSONObject;

import android.accounts.Account;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.location.Location;
import android.media.ExifInterface;
import android.net.Uri;
import android.provider.MediaStore.Images.Media;
import android.provider.MediaStore.MediaColumns;
import android.util.Log;
import edu.mit.mobile.android.content.ProviderUtils;
import edu.mit.mobile.android.content.column.BooleanColumn;
import edu.mit.mobile.android.content.column.DBColumn;
import edu.mit.mobile.android.content.column.DatetimeColumn;
import edu.mit.mobile.android.content.column.TextColumn;
import edu.mit.mobile.android.locast.Constants;
import edu.mit.mobile.android.locast.net.NetworkProtocolException;
import edu.mit.mobile.android.locast.sync.AbsMediaSync;

public abstract class CastMedia extends JsonSyncableItem {
  private static final String TAG = CastMedia.class.getSimpleName();

  /**
   * A textual caption for the media. Optional.
   */
  @DBColumn(type = TextColumn.class)
  public final static String COL_CAPTION = "caption";

  @DBColumn(type = DatetimeColumn.class)
  public final static String COL_CAPTURE_TIME = "capture_time";

  /**
   * The main content. This is a public URL.
   */
  @DBColumn(type = TextColumn.class)
  public final static String COL_MEDIA_URL = "media_url";

  /**
   * The main content. This links to an optional local copy of the media.
   */
  @DBColumn(type = TextColumn.class)
  public final static String COL_LOCAL_URL = "local_url";

  /**
   * The content type of the media.
   */
  @DBColumn(type = TextColumn.class)
  public final static String COL_MIME_TYPE = "mimetype";

  /**
   * Whether or not to keep an offline copy. If set to true, the media sync engine will download a
   * copy.
   */
  @DBColumn(type = BooleanColumn.class)
  public final static String COL_KEEP_OFFLINE = "offline";

  // TODO move this to ImageContent, etc.
  @DBColumn(type = TextColumn.class)
  public final static String COL_THUMB_LOCAL = "local_thumb"; // filename of the local thumbnail

  /**
   * If true, the media has been changed locally and should be re-uploaded.
   */
  @DBColumn(type = BooleanColumn.class, defaultValueInt = 0)
  public final static String COL_MEDIA_DIRTY = "media_dirty";

  //@formatter:off
    public static final String
        MIMETYPE_HTML = "text/html",
        MIMETYPE_3GPP = "video/3gpp",
        MIMETYPE_MPEG4 = "video/mpeg4";
    //@formatter:on

  public CastMedia(Cursor c) {
    super(c);
  }

  public Uri getMedia(int mediaCol, int mediaLocalCol) {
    Uri media;
    if (!isNull(mediaLocalCol)) {
      media = Uri.parse(getString(mediaLocalCol));
    } else if (!isNull(mediaCol)) {
      media = Uri.parse(getString(mediaCol));
    } else {
      media = null;
    }
    return media;
  }

  /**
   * Given a cursor pointing to a cast media item, attempt to resolve an intent that will show it.
   *
   * @param context
   * @param c
   *            a cast media cursor pointing to the desired item
   * @param castMediaDir
   * @return an intent that will show the media or null if there are none found
   */
  public static Intent showMedia(Context context, Cursor c, Uri castMediaDir) {
    final String mediaString = c.getString(c.getColumnIndex(CastMedia.COL_MEDIA_URL));
    final String locMediaString = c.getString(c.getColumnIndex(CastMedia.COL_LOCAL_URL));
    String mimeType = null;

    Uri media;

    if (locMediaString != null) {
      media = Uri.parse(locMediaString);
      if ("file".equals(media.getScheme())) {
        mimeType = c.getString(c.getColumnIndex(CastMedia.COL_MIME_TYPE));
      }

    } else if (mediaString != null) {
      media = Uri.parse(mediaString);
      mimeType = c.getString(c.getColumnIndex(CastMedia.COL_MIME_TYPE));

      // we strip this because we don't really want to force them to go to the browser.
      if ("text/html".equals(mimeType)) {
        mimeType = null;
      }
    } else {
      Log.e(TAG, "asked to show media for " + castMediaDir + " but there was nothing to show");
      return null;
    }

    final Intent i = new Intent(Intent.ACTION_VIEW);
    i.setDataAndType(media, mimeType);

    final PackageManager pm = context.getPackageManager();

    // if we are set up to play back the content locally and it's a video, do such...
    if (mimeType != null && mimeType.startsWith("video/")) {
      final Intent localPlayback = new Intent(Intent.ACTION_VIEW, ContentUris.withAppendedId(
          castMediaDir, c.getLong(c.getColumnIndex(CastMedia._ID))));

      if (localPlayback.resolveActivity(pm) != null) {
        return localPlayback;
      }
    }

    // setting the MIME type for URLs doesn't work.
    if (i.resolveActivity(pm) != null) {
      return i;
    }

    // try it again, but without a mime type.
    if (mimeType != null) {
      i.setDataAndType(media, null);
    }

    if (i.resolveActivity(pm) != null) {
      return i;
    }

    // Oh bother, nothing worked.
    return null;

  }

  /**
   * Adds the given media to a castMedia uri.
   *
   * If the media is a content:// uri, queries the content resolver to get the needed information.
   *
   * @param context
   * @param castMedia
   *            uri of the cast media dir to insert into
   * @param content
   *            uri of the media to add
   * @return a summary of the information discovered from the content uri
   * @throws MediaProcessingException
   */
  public static CastMediaInfo addMedia(Context context, Account me, Uri castMedia, Uri content,
      ContentValues cv) throws MediaProcessingException {

    final ContentResolver cr = context.getContentResolver();

    final CastMediaInfo castMediaInfo = toMediaInfo(context, content, cv);

    if (Constants.DEBUG) {
      Log.d(TAG, "addMedia(" + castMedia + ", " + cv + ")");
    }

    cv.put(COL_MEDIA_DIRTY, true);

    castMediaInfo.castMediaItem = cr.insert(castMedia, cv);

    return castMediaInfo;
  }

  /**
   * <p>
   * Updates the cast media item to use a new media item.
   * </p>
   *
   * <p>
   * If the media is a content:// uri, queries the content resolver to get the needed information.
   * </p>
   *
   * @param context
   * @param castMediaItem
   *            uri of the castMedia item to update
   * @param content
   *            uri of the local media file to update
   * @return a summary of the information discovered from the content uri
   * @throws MediaProcessingException
   */
  public static CastMediaInfo updateMedia(Context context, Account me, Uri castMediaItem,
      Uri content, ContentValues cv) throws MediaProcessingException {

    final ContentResolver cr = context.getContentResolver();

    final CastMediaInfo castMediaInfo = toMediaInfo(context, content, cv);
    castMediaInfo.castMediaItem = castMediaItem;

    if (Constants.DEBUG) {
      Log.d(TAG, "addMedia(" + castMediaItem + ", " + cv + ")");
    }

    cv.put(COL_MEDIA_DIRTY, true);

    final int updates = cr.update(castMediaItem, cv, null, null);

    return castMediaInfo;
  }

  /**
   * Turns the given content into a new or updated cast media.
   *
   * If the media is a content:// uri, queries the content resolver to get the needed information.
   *
   * @param context
   * @param castMedia
   *            uri of the cast media dir to insert into
   * @param content
   *            uri of the media to add
   * @return a summary of the information discovered from the content uri
   * @throws MediaProcessingException
   */
  protected static CastMediaInfo toMediaInfo(Context context, Uri content, ContentValues cv)
      throws MediaProcessingException {

    final ContentResolver cr = context.getContentResolver();

    final long now = System.currentTimeMillis();

    final String mimeType = getContentType(cr, content);
    cv.put(CastMedia.COL_MIME_TYPE, mimeType);

    String mediaPath;

    // for media that use content URIs, we need to query the content provider to look up all the
    // details

    final CastMediaInfo castMediaInfo = new CastMediaInfo();

    if ("content".equals(content.getScheme())) {
      mediaPath = extractContent(cr, content, cv, castMediaInfo);

    } else if ("file".equals(content.getScheme())) {
      final String path = content.getPath();
      if (!new File(path).exists()) {
        throw new MediaProcessingException("specified media file does not exist: "
            + content);
      }
      mediaPath = content.toString();

      if ("image/jpeg".equals(mimeType)) {
        try {
          String exifDateTime = "";
          final ExifInterface exif = new ExifInterface(path);
          exifDateTime = exif.getAttribute(ExifInterface.TAG_DATETIME);
          if (exifDateTime != null && exifDateTime.length() > 0) {
            cv.put(CastMedia.COL_CAPTURE_TIME, exifDateTime);
          }

        } catch (final IOException ioex) {
          Log.e(TAG, "EXIF: Couldn't find media: " + path);
        }
      }
    } else {
      throw new MediaProcessingException("Don't know how to process URI scheme "
          + content.getScheme() + " for " + content);
    }

    // ensure that there's always a capture time, even if it's faked.
    if (!cv.containsKey(CastMedia.COL_CAPTURE_TIME)) {
      Log.w(TAG, "faking capture time with current time");
      cv.put(CastMedia.COL_CAPTURE_TIME, now);
    }

    // if it's an image, we can use the source file for the thumbnail.
    if (mimeType.startsWith("image/")) {
      cv.put(CastMedia.COL_THUMB_LOCAL, mediaPath);
    }
    cv.put(CastMedia.COL_LOCAL_URL, mediaPath);

    return castMediaInfo;

  }

  private static String extractContent(ContentResolver cr, Uri content, ContentValues cv,
      CastMediaInfo castMediaInfo) {
    String mediaPath = null;

    final Cursor c = cr.query(content, new String[] { MediaColumns._ID, MediaColumns.DATA,
        MediaColumns.TITLE, Media.LATITUDE, Media.LONGITUDE }, null, null, null);
    try {
      if (c.moveToFirst()) {
        final String title = c.getString(c.getColumnIndexOrThrow(MediaColumns.TITLE));
        cv.put(CastMedia.COL_CAPTION, title);
        castMediaInfo.title = title;
        mediaPath = "file://" + c.getString(c.getColumnIndexOrThrow(MediaColumns.DATA));
        castMediaInfo.path = mediaPath;

        // if the current location is null, infer it from the first media that's added.
        if (castMediaInfo.location == null) {
          final int latCol = c.getColumnIndex(Media.LATITUDE);
          final int lonCol = c.getColumnIndex(Media.LONGITUDE);
          final double lat = c.getDouble(latCol);
          final double lon = c.getDouble(lonCol);

          final boolean isInArmpit = lat == 0 && lon == 0; // Sorry, people in boats off
                                    // the coast of Ghana, but
                                    // you're an unfortunate
                                    // edge case...
          if (!c.isNull(latCol) && !c.isNull(lonCol) && !isInArmpit) {

            castMediaInfo.location = new Location("manual");
            castMediaInfo.location.setLatitude(lat);
            castMediaInfo.location.setLatitude(lon);
          }
        }
      }
    } finally {
      c.close();
    }

    return mediaPath;
  }

  private static String getContentType(ContentResolver cr, Uri content) {
    String mimeType = cr.getType(content);
    if (mimeType == null) {
      mimeType = CastMedia.guessContentTypeFromUrl(content.toString());
    }
    return mimeType;
  }

  public static class CastMediaInfo {

    /**
     * The content's title
     */
    public String title;

    /**
     * the content's MIME type
     */
    public String mimeType;
    /**
     * the content:// URI of the newly created cast media item
     */
    public Uri castMediaItem;
    /**
     * if location information was discovered from the media's metadata, this location is
     * extracted. Otherwise null.
     */
    public Location location;
    /**
     * the path on disk to the media
     */
    public String path;

    public CastMediaInfo() {

    }

    /**
     * @param path
     * @param mimeType
     * @param castMediaItem
     * @param location
     */
    public CastMediaInfo(String path, String mimeType, Uri castMediaItem, Location location) {
      this.path = path;
      this.mimeType = mimeType;
      this.castMediaItem = castMediaItem;
      this.location = location;
    }

  }

  public static Uri getThumbnail(Cursor c, int thumbCol, int thumbLocalCol) {
    Uri thumbnail;
    if (!c.isNull(thumbLocalCol)) {
      thumbnail = Uri.parse(c.getString(thumbLocalCol));
    } else if (!c.isNull(thumbCol)) {
      thumbnail = Uri.parse(c.getString(thumbCol));
    } else {
      thumbnail = null;
    }
    return thumbnail;
  }

  /**
   * Guesses the mime type from the URL
   *
   * @param url
   * @return the inferred mime type based on the file extension or null if it can't determine one
   */
  public static String guessContentTypeFromUrl(String url) {

    // this was improved in Gingerbread
    // http://code.google.com/p/android/issues/detail?id=10100
    // so we have some pre-defined types here so we can make sure to return SOMETHING.
    String mimeType = URLConnection.guessContentTypeFromName(url);
    if (mimeType != null) {
      return mimeType;
    }

    if (url.endsWith(".jpg") || url.endsWith(".jpeg")) {
      mimeType = "image/jpeg";

    } else if (url.endsWith(".3gp")) {
      mimeType = "video/3gpp";

    } else if (url.endsWith(".mp4") || url.endsWith(".mpeg4")) {
      mimeType = "video/mp4";

    } else if (url.endsWith(".png")) {
      mimeType = "image/png";
    }

    return mimeType;
  }

  public final static ItemSyncMap SYNC_MAP = new ItemSyncMap();

  public static class ItemSyncMap extends JsonSyncableItem.ItemSyncMap {
    /**
         *
         */
    private static final long serialVersionUID = 8477549708016150941L;

    public ItemSyncMap() {
      super();

      addFlag(FLAG_PARENT_MUST_SYNC_FIRST);

      // put("_resources", );

      // no MIME type is passed with a link media type, so we need to add one in.
      put("_content_type", new SyncCustom("content_type", SyncItem.SYNC_BOTH) {

        @Override
        public Object toJSON(Context context, Uri localItem, Cursor c, String lProp)
            throws JSONException, NetworkProtocolException, IOException {
          String mimeType = c.getString(c.getColumnIndex(COL_MIME_TYPE));
          final String localUri = c.getString(c.getColumnIndex(COL_LOCAL_URL));

          if (mimeType == null && localUri != null) {

            // XXX context.getContentResolver().getType(url);

            mimeType = guessContentTypeFromUrl(localUri);
            if (mimeType != null) {
              Log.d(TAG, "guessed MIME type from uri: " + localUri + ": " + mimeType);
            }
          }

          if (mimeType == null) {
            return null;
          }

          if (mimeType.startsWith("video/")) {
            return "videomedia";
          } else if (mimeType.startsWith("image/")) {
            return "imagemedia";
          } else {
            return null;
          }
        }

        @Override
        public ContentValues fromJSON(Context context, Uri localItem, JSONObject item,
            String lProp) throws JSONException, NetworkProtocolException, IOException {
          final ContentValues cv = new ContentValues();
          final String content_type = item.getString(remoteKey);

          if ("linkedmedia".equals(content_type)) {
            cv.put(COL_MIME_TYPE, MIMETYPE_HTML);
          }

          return cv;
        }
      });

      put(COL_CAPTURE_TIME, new SyncFieldMap("capture_time", SyncFieldMap.DATE,
          SyncItem.FLAG_OPTIONAL));

      put(COL_CAPTION, new SyncFieldMap("caption", SyncFieldMap.STRING,
          SyncItem.FLAG_OPTIONAL));
    }

    @Override
    public void onPostSyncItem(Context context, Account account, Uri uri, JSONObject item,
        boolean updated) throws SyncException, IOException {
      super.onPostSyncItem(context, account, uri, item, updated);
      if (uri != null) {
        final Uri parent = ProviderUtils.removeLastPathSegment(uri);

        if (Constants.DEBUG) {
          Log.d(TAG, "Starting media sync for " + parent);
        }
        context.startService(new Intent(AbsMediaSync.ACTION_SYNC_RESOURCES, parent));
      } else if (Constants.DEBUG) {
        Log.w(TAG, "no uri provided when calling onPostSyncItem()");
      }
    }
  }
}




Java Source Code List

com.beoui.geocell.GeocellLogger.java
com.beoui.geocell.GeocellQueryEngine.java
com.beoui.geocell.GeocellUtils.java
com.beoui.geocell.annotations.Geocells.java
com.beoui.geocell.annotations.Latitude.java
com.beoui.geocell.annotations.Longitude.java
com.beoui.geocell.comparator.DoubleTupleComparator.java
com.beoui.geocell.comparator.LocationComparableTuple.java
com.beoui.geocell.model.BoundingBox.java
com.beoui.geocell.model.CostFunction.java
com.beoui.geocell.model.DefaultCostFunction.java
com.beoui.geocell.model.GeocellQuery.java
com.beoui.geocell.model.LocationCapable.java
com.beoui.geocell.model.Point.java
com.beoui.geocell.model.Tuple.java
com.stackoverflow.ArrayUtils.java
com.stackoverflow.CollectionUtils.java
com.stackoverflow.MediaUtils.java
com.stackoverflow.Predicate.java
edu.mit.mobile.android.MelAndroid.java
edu.mit.mobile.android.json.JSONArrayAdapter.java
edu.mit.mobile.android.locast.Constants.java
edu.mit.mobile.android.locast.accounts.AbsAccountChangeReceiver.java
edu.mit.mobile.android.locast.accounts.AbsLocastAuthenticationService.java
edu.mit.mobile.android.locast.accounts.AbsLocastAuthenticatorActivity.java
edu.mit.mobile.android.locast.accounts.AbsLocastAuthenticator.java
edu.mit.mobile.android.locast.accounts.AbsRegisterActivity.java
edu.mit.mobile.android.locast.accounts.LogoutFragment.java
edu.mit.mobile.android.locast.app.LocastApplication.java
edu.mit.mobile.android.locast.data.AbsComment.java
edu.mit.mobile.android.locast.data.AbsResourcesSync.java
edu.mit.mobile.android.locast.data.CastMedia.java
edu.mit.mobile.android.locast.data.ImageContent.java
edu.mit.mobile.android.locast.data.JSONSyncableIdenticalChildFinder.java
edu.mit.mobile.android.locast.data.JsonSyncableItem.java
edu.mit.mobile.android.locast.data.MediaProcessingException.java
edu.mit.mobile.android.locast.data.NoPublicPath.java
edu.mit.mobile.android.locast.data.OrderedList.java
edu.mit.mobile.android.locast.data.ResourcesSync.java
edu.mit.mobile.android.locast.data.SyncException.java
edu.mit.mobile.android.locast.data.SyncItemDeletedException.java
edu.mit.mobile.android.locast.data.SyncMapException.java
edu.mit.mobile.android.locast.data.SyncMap.java
edu.mit.mobile.android.locast.data.VideoContent.java
edu.mit.mobile.android.locast.data.interfaces.AuthorableUtils.java
edu.mit.mobile.android.locast.data.interfaces.Authorable.java
edu.mit.mobile.android.locast.data.interfaces.CommentableUtils.java
edu.mit.mobile.android.locast.data.interfaces.Commentable.java
edu.mit.mobile.android.locast.data.interfaces.FavoritableUtils.java
edu.mit.mobile.android.locast.data.interfaces.Favoritable.java
edu.mit.mobile.android.locast.data.interfaces.LocatableUtils.java
edu.mit.mobile.android.locast.data.interfaces.Locatable.java
edu.mit.mobile.android.locast.data.interfaces.PrivatelyAuthorableUtils.java
edu.mit.mobile.android.locast.data.interfaces.PrivatelyAuthorable.java
edu.mit.mobile.android.locast.data.interfaces.TitledUtils.java
edu.mit.mobile.android.locast.data.interfaces.Titled.java
edu.mit.mobile.android.locast.data.tags.IdenticalTagFinder.java
edu.mit.mobile.android.locast.data.tags.TagSyncField.java
edu.mit.mobile.android.locast.data.tags.Tag.java
edu.mit.mobile.android.locast.data.tags.TaggableUtils.java
edu.mit.mobile.android.locast.data.tags.TaggableWrapper.java
edu.mit.mobile.android.locast.data.tags.Taggable.java
edu.mit.mobile.android.locast.net.ClientResponseException.java
edu.mit.mobile.android.locast.net.LocastApplicationCallbacks.java
edu.mit.mobile.android.locast.net.NetworkClient.java
edu.mit.mobile.android.locast.net.NetworkProtocolException.java
edu.mit.mobile.android.locast.sync.AbsLocastAccountSyncService.java
edu.mit.mobile.android.locast.sync.AbsMediaSync.java
edu.mit.mobile.android.locast.sync.LocastSimpleSyncService.java
edu.mit.mobile.android.locast.sync.LocastSyncService.java
edu.mit.mobile.android.locast.sync.LocastSyncStatusObserver.java
edu.mit.mobile.android.locast.sync.NotificationProgressListener.java
edu.mit.mobile.android.locast.sync.SyncColumns.java
edu.mit.mobile.android.locast.sync.SyncEngine.java
edu.mit.mobile.android.locast.sync.SyncableProvider.java
edu.mit.mobile.android.locast.sync.SyncableSimpleContentProvider.java
edu.mit.mobile.android.locast.sync.Syncable.java
edu.mit.mobile.android.locast.widget.RemoteTagsAdapter.java
edu.mit.mobile.android.locast.widget.TagButton.java
edu.mit.mobile.android.locast.widget.TagListView.java
edu.mit.mobile.android.locast.widget.TagList.java
edu.mit.mobile.android.locast.widget.TagsLoaderCallbacks.java
edu.mit.mobile.android.location.IncrementalLocator.java
se.fnord.android.layout.PredicateLayout.java