Android Open Source - vanilindy Song






From Project

Back to project page vanilindy.

License

The source code is released under:

Apache License

If you think the Android project vanilindy 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

/*
 * Copyright (C) 2010, 2011 Christopher Eby <kreed@kreed.org>
 */*from  w  w  w.j a  va  2  s.  c o m*/
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package ch.blinkenlights.android.vanilla;

import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.provider.MediaStore;
import android.util.LruCache;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;

import android.util.Log;

/**
 * Represents a Song backed by the MediaStore. Includes basic metadata and
 * utilities to retrieve songs from the MediaStore.
 */
public class Song implements Comparable<Song> {
  /**
   * Indicates that this song was randomly selected from all songs.
   */
  public static final int FLAG_RANDOM = 0x1;
  /**
   * If set, this song has no cover art. If not set, this song may or may not
   * have cover art.
   */
  public static final int FLAG_NO_COVER = 0x2;
  /**
   * The number of flags.
   */
  public static final int FLAG_COUNT = 2;
  /**
   * Use all cover providers to load cover art
   */
  public static final int COVER_MODE_ALL = 0xF;
  /**
   * Use androids builtin cover mechanism to load covers
   */
  public static final int COVER_MODE_ANDROID = 0x1;
  /**
   * Use vanilla musics cover load mechanism
   */
  public static final int COVER_MODE_VANILLA = 0x2;
  /**
   * Use vanilla musics SHADOW cover load mechanism
   */
  public static final int COVER_MODE_SHADOW = 0x4;


  public static final String[] EMPTY_PROJECTION = {
    MediaStore.Audio.Media._ID,
  };

  public static final String[] FILLED_PROJECTION = {
    MediaStore.Audio.Media._ID,
    MediaStore.Audio.Media.DATA,
    MediaStore.Audio.Media.TITLE,
    MediaStore.Audio.Media.ALBUM,
    MediaStore.Audio.Media.ARTIST,
    MediaStore.Audio.Media.ALBUM_ID,
    MediaStore.Audio.Media.ARTIST_ID,
    MediaStore.Audio.Media.DURATION,
    MediaStore.Audio.Media.TRACK,
  };

  public static final String[] EMPTY_PLAYLIST_PROJECTION = {
    MediaStore.Audio.Playlists.Members.AUDIO_ID,
  };

  public static final String[] FILLED_PLAYLIST_PROJECTION = {
    MediaStore.Audio.Playlists.Members.AUDIO_ID,
    MediaStore.Audio.Playlists.Members.DATA,
    MediaStore.Audio.Playlists.Members.TITLE,
    MediaStore.Audio.Playlists.Members.ALBUM,
    MediaStore.Audio.Playlists.Members.ARTIST,
    MediaStore.Audio.Playlists.Members.ALBUM_ID,
    MediaStore.Audio.Playlists.Members.ARTIST_ID,
    MediaStore.Audio.Playlists.Members.DURATION,
    MediaStore.Audio.Playlists.Members.TRACK,
  };

  private class LruCacheKey {
    long id;
    long artistId;
    long albumId;
    String path;

    public LruCacheKey(long id, long artistId, long albumId, String path) {
      this.id = id;
      this.artistId = artistId;
      this.albumId = albumId;
      this.path = path;
    }

    @Override
    public boolean equals(Object obj) {
//      if (obj instanceof LruCacheKey && this.albumId == ((LruCacheKey)obj).albumId && this.artistId == ((LruCacheKey)obj).artistId) {
//        return true;
//      }
      return false;
    }

    @Override
    public int hashCode() {
      return (int)( 0xFFFFFF & (this.artistId + this.albumId) );
    }

    @Override
    public String toString() {
      return "LruCacheKey<"+this.id+"> = "+this.path;
    }

  }

  /**
   * A cache of 6 MiB of covers.
   */
  private static class CoverCache extends LruCache<LruCacheKey, Bitmap> {
    private final Context mContext;

    // Possible coverart names if we are going to load the cover on our own
    private static String[] coverNames = { "cover.jpg", "cover.png", "album.jpg", "album.png", "artwork.jpg", "artwork.png", "art.jpg", "art.png" };

    public CoverCache(Context context)
    {
      super(6 * 1024 * 1024);
      mContext = context;
    }

    @Override
    public Bitmap create(LruCacheKey key)
    {
      try {
        InputStream inputStream = null;
        InputStream sampleInputStream = null; // same as inputStream but used for getSampleSize

        if ((mCoverLoadMode & COVER_MODE_VANILLA) != 0) {
          String basePath = (new File(key.path)).getParentFile().getAbsolutePath(); // ../ of the currently playing file
          for (String coverFile: coverNames) {
            File guessedFile = new File( basePath + "/" + coverFile);
            if (guessedFile.exists() && !guessedFile.isDirectory()) {
              inputStream = new FileInputStream(guessedFile);
              sampleInputStream = new FileInputStream(guessedFile);
              break;
            }
          }
        }

        if (inputStream == null && (mCoverLoadMode & COVER_MODE_SHADOW) != 0) {
          String[] projection = new String [] { MediaStore.Audio.Media.ARTIST, MediaStore.Audio.Media.ALBUM };
          QueryTask query = MediaUtils.buildQuery(MediaUtils.TYPE_SONG, key.id, projection, null);
          Cursor cursor = query.runQuery(mContext.getContentResolver());
          if (cursor != null) {
            if (cursor.getCount() > 0) {
              cursor.moveToNext();
              String thisArtist = cursor.getString(0);
              String thisAlbum = cursor.getString(1);
              String shadowPath = "/sdcard/Music/.vanilla/"+(thisArtist.replaceAll("/", "_"))+"/"+(thisAlbum.replaceAll("/", "_"))+".jpg";

              File guessedFile = new File(shadowPath);
              if (guessedFile.exists() && !guessedFile.isDirectory()) {
                inputStream = new FileInputStream(guessedFile);
                sampleInputStream = new FileInputStream(guessedFile);
              }
            }
            cursor.close();
          }
        }

        if (inputStream == null && (mCoverLoadMode & COVER_MODE_ANDROID) != 0) {
          Uri uri =  Uri.parse("content://media/external/audio/media/" + key.id + "/albumart");
          ContentResolver res = mContext.getContentResolver();
          inputStream = res.openInputStream(uri);
          sampleInputStream = res.openInputStream(uri);
        }

        if (inputStream != null) {
          BitmapFactory.Options bopts = new BitmapFactory.Options();
          bopts.inPreferredConfig  = Bitmap.Config.RGB_565;
          bopts.inJustDecodeBounds = true;

          final int inSampleSize   = getSampleSize(sampleInputStream, bopts);

          /* reuse bopts: we are now REALLY going to decode the image */
          bopts.inJustDecodeBounds = false;
          bopts.inSampleSize       = inSampleSize;
          return BitmapFactory.decodeStream(inputStream, null, bopts);
        }
      } catch (Exception e) {
        // no cover art found
        Log.v("VanillaMusic", "Loading coverart for "+key+" failed with exception "+e);
      }

      return null;
    }

    /**
     * Guess a good sampleSize value for given inputStream
     */
    private static int getSampleSize(InputStream inputStream, BitmapFactory.Options bopts) {
      int sampleSize = 1;     /* default sample size                   */
      long maxVal = 600*600;  /* max number of pixels we are accepting */

      BitmapFactory.decodeStream(inputStream, null, bopts);
      long hasPixels = bopts.outHeight * bopts.outWidth;
      if(hasPixels > maxVal) {
        sampleSize = Math.round((int)Math.sqrt((float) hasPixels / (float) maxVal));
      }
      return sampleSize;
    }

    @Override
    protected int sizeOf(LruCacheKey key, Bitmap value)
    {
      return value.getRowBytes() * value.getHeight();
    }
  }

  /**
   * The cache instance.
   */
  private static CoverCache sCoverCache = null;

  /**
   * Bitmask on how we are going to load coverart
   */
  public static int mCoverLoadMode = 0;

  /**
   * We will evict our own cache if set to true
   */
  public static boolean mFlushCoverCache = false;

  /**
   * Id of this song in the MediaStore
   */
  public long id;
  /**
   * Id of this song's album in the MediaStore
   */
  public long albumId;
  /**
   * Id of this song's artist in the MediaStore
   */
  public long artistId;

  /**
   * Path to the data for this song
   */
  public String path;

  /**
   * Song title
   */
  public String title;
  /**
   * Album name
   */
  public String album;
  /**
   * Artist name
   */
  public String artist;

  /**
   * Length of the song in milliseconds.
   */
  public long duration;
  /**
   * The position of the song in its album.
   */
  public int trackNumber;

  /**
   * Song flags. Currently {@link #FLAG_RANDOM} or {@link #FLAG_NO_COVER}.
   */
  public int flags;

  /**
   * Initialize the song with the specified id. Call populate to fill fields
   * in the song.
   */
  public Song(long id)
  {
    this.id = id;
  }

  /**
   * Initialize the song with the specified id and flags. Call populate to
   * fill fields in the song.
   */
  public Song(long id, int flags)
  {
    this.id = id;
    this.flags = flags;
  }

  /**
   * Return true if this song was retrieved from randomSong().
   */
  public boolean isRandom()
  {
    return (flags & FLAG_RANDOM) != 0;
  }

  /**
   * Populate fields with data from the supplied cursor.
   *
   * @param cursor Cursor queried with FILLED_PROJECTION projection
   */
  public void populate(Cursor cursor)
  {
    id = cursor.getLong(0);
    path = cursor.getString(1);
    title = cursor.getString(2);
    album = cursor.getString(3);
    artist = cursor.getString(4);
    albumId = cursor.getLong(5);
    artistId = cursor.getLong(6);
    duration = cursor.getLong(7);
    trackNumber = cursor.getInt(8);
  }

  /**
   * Get the id of the given song.
   *
   * @param song The Song to get the id from.
   * @return The id, or 0 if the given song is null.
   */
  public static long getId(Song song)
  {
    if (song == null)
      return 0;
    return song.id;
  }

  /**
   * Query the album art for this song.
   *
   * @param context A context to use.
   * @return The album art or null if no album art could be found
   */
  public Bitmap getCover(Context context)
  {
    if (mCoverLoadMode == 0 || id == -1 || (flags & FLAG_NO_COVER) != 0)
      return null;

    if (sCoverCache == null)
      sCoverCache = new CoverCache(context.getApplicationContext());

    if (mFlushCoverCache) {
      mFlushCoverCache = false;
      sCoverCache.evictAll();
    }

    LruCacheKey key = new LruCacheKey(id, artistId, albumId, path);
    Bitmap cover = sCoverCache.get(key);

    if (cover == null)
      flags |= FLAG_NO_COVER;
    return cover;
  }

  @Override
  public String toString()
  {
    return String.format("%d %d %s", id, albumId, path);
  }

  /**
   * Compares the album ids of the two songs; if equal, compares track order.
   */
  @Override
  public int compareTo(Song other)
  {
    if (albumId == other.albumId)
      return trackNumber - other.trackNumber;
    if (albumId > other.albumId)
      return 1;
    return -1;
  }
}




Java Source Code List

android.support.v4.view.PagerAdapter.java
android.support.v4.view.ViewPager.java
ch.blinkenlights.android.vanilla.ActionBarControls.java
ch.blinkenlights.android.vanilla.Action.java
ch.blinkenlights.android.vanilla.BastpUtil.java
ch.blinkenlights.android.vanilla.BuildConfig.java
ch.blinkenlights.android.vanilla.CompatHoneycomb.java
ch.blinkenlights.android.vanilla.CompatIcs.java
ch.blinkenlights.android.vanilla.CoverBitmap.java
ch.blinkenlights.android.vanilla.CoverView.java
ch.blinkenlights.android.vanilla.DragListView.java
ch.blinkenlights.android.vanilla.DragTextView.java
ch.blinkenlights.android.vanilla.FileSystemAdapter.java
ch.blinkenlights.android.vanilla.FilebrowserStartActivity.java
ch.blinkenlights.android.vanilla.FilebrowserStartAdapter.java
ch.blinkenlights.android.vanilla.FourLongWidget.java
ch.blinkenlights.android.vanilla.FourSquareWidget.java
ch.blinkenlights.android.vanilla.FourWhiteWidget.java
ch.blinkenlights.android.vanilla.FullPlaybackActivity.java
ch.blinkenlights.android.vanilla.IdlePreference.java
ch.blinkenlights.android.vanilla.LibraryActivity.java
ch.blinkenlights.android.vanilla.LibraryAdapter.java
ch.blinkenlights.android.vanilla.LibraryPagerAdapter.java
ch.blinkenlights.android.vanilla.Limiter.java
ch.blinkenlights.android.vanilla.ListPreferenceSummary.java
ch.blinkenlights.android.vanilla.MediaAdapter.java
ch.blinkenlights.android.vanilla.MediaButtonReceiver.java
ch.blinkenlights.android.vanilla.MediaUtils.java
ch.blinkenlights.android.vanilla.MiniPlaybackActivity.java
ch.blinkenlights.android.vanilla.MusicAlphabetIndexer.java
ch.blinkenlights.android.vanilla.NewPlaylistDialog.java
ch.blinkenlights.android.vanilla.OneCellWidget.java
ch.blinkenlights.android.vanilla.PlayCountsHelper.java
ch.blinkenlights.android.vanilla.PlaybackActivity.java
ch.blinkenlights.android.vanilla.PlaybackService.java
ch.blinkenlights.android.vanilla.PlaylistActivity.java
ch.blinkenlights.android.vanilla.PlaylistAdapter.java
ch.blinkenlights.android.vanilla.Playlist.java
ch.blinkenlights.android.vanilla.PrefKeys.java
ch.blinkenlights.android.vanilla.PreferencesActivity.java
ch.blinkenlights.android.vanilla.PreferencesBackupAgent.java
ch.blinkenlights.android.vanilla.QueryTask.java
ch.blinkenlights.android.vanilla.ReadaheadThread.java
ch.blinkenlights.android.vanilla.SeekBarPreference.java
ch.blinkenlights.android.vanilla.ShowQueueActivity.java
ch.blinkenlights.android.vanilla.ShowQueueAdapter.java
ch.blinkenlights.android.vanilla.SongTimeline.java
ch.blinkenlights.android.vanilla.Song.java
ch.blinkenlights.android.vanilla.TabOrderActivity.java
ch.blinkenlights.android.vanilla.TabOrderAdapter.java
ch.blinkenlights.android.vanilla.WidgetD.java
ch.blinkenlights.android.vanilla.WidgetE.java
ch.blinkenlights.bastp.Bastp.java
ch.blinkenlights.bastp.Common.java
ch.blinkenlights.bastp.FlacFile.java
ch.blinkenlights.bastp.ID3v2File.java
ch.blinkenlights.bastp.LameHeader.java
ch.blinkenlights.bastp.OggFile.java
com.viewpagerindicator.TabPageIndicator.java