Android Open Source - yammp Music Utils






From Project

Back to project page yammp.

License

The source code is released under:

GNU Lesser General Public License

If you think the Android project yammp 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) 2012 The MusicMod Project
 *//  ww  w.j av  a2s  .  c  om
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.yammp.util;

import java.io.File;
import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.lang.ref.SoftReference;
import java.util.Arrays;
import java.util.Formatter;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import org.yammp.Constants;
import org.yammp.IMusicPlaybackService;
import org.yammp.MusicPlaybackService;
import org.yammp.R;

import android.app.Activity;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.res.Resources;
import android.database.Cursor;
import android.database.sqlite.SQLiteException;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.provider.MediaStore;
import android.provider.MediaStore.Audio;
import android.provider.MediaStore.Audio.Genres;
import android.provider.MediaStore.Audio.Playlists;
import android.text.format.Time;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.widget.ImageView;
import android.widget.Toast;

public class MusicUtils implements Constants {

  public static IMusicPlaybackService mService = null;

  private static HashMap<Context, ServiceBinder> mConnectionMap = new HashMap<Context, ServiceBinder>();

  private final static long[] mEmptyList = new long[0];

  private static ContentValues[] sContentValuesCache = null;

  /*
   * Try to use String.format() as little as possible, because it creates a
   * new Formatter every time you call it, which is very inefficient. Reusing
   * an existing Formatter more than tripled the speed of makeTimeString().
   * This Formatter/StringBuilder are also used by makeAlbumSongsLabel()
   */
  private static StringBuilder sFormatBuilder = new StringBuilder();

  private static Formatter sFormatter = new Formatter(sFormatBuilder, Locale.getDefault());

  private static final Object[] sTimeArgs = new Object[5];

  private static final BitmapFactory.Options mBitmapOptionsCache = new BitmapFactory.Options();

  private static final BitmapFactory.Options mBitmapOptions = new BitmapFactory.Options();

  private static final Uri mArtworkUri = Uri.parse("content://media/external/audio/albumart");

  private static final HashMap<Long, Bitmap> mArtBitmapCache = new HashMap<Long, Bitmap>();

  private static final HashMap<Long, Drawable> mArtCache = new HashMap<Long, Drawable>();

  private static int mArtCacheId = -1;

  static {
    // for the cache,
    // 565 is faster to decode and display
    // and we don't want to dither here because the image will be scaled
    // down later
    mBitmapOptionsCache.inPreferredConfig = Bitmap.Config.RGB_565;
    mBitmapOptionsCache.inDither = false;

    mBitmapOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
    mBitmapOptions.inDither = false;
  }

  private static LogEntry[] mMusicLog = new LogEntry[100];

  private static int mLogPtr = 0;

  private static Time mTime = new Time();

  public static void addToCurrentPlaylist(Context context, long[] list) {

    if (mService == null) return;
    try {
      mService.enqueue(list, MusicPlaybackService.ACTION_LAST);
      String message = context.getResources().getQuantityString(
          R.plurals.NNNtrackstoplaylist, list.length, Integer.valueOf(list.length));
      Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
    } catch (RemoteException ex) {
    }
  }

  public static void addToFavorites(Context context, long id) {

    long favorites_id;

    if (id < 0) {
      // this shouldn't happen (the menuitems shouldn't be visible
      // unless the selected item represents something playable
      Log.e(LOGTAG_MUSICUTILS, "playlist id " + id + " is invalid.");
    } else {
      ContentResolver resolver = context.getContentResolver();
      // need to determine the number of items currently in the playlist,
      // so the play_order field can be maintained.

      String favorites_where = Audio.Playlists.NAME + "='" + PLAYLIST_NAME_FAVORITES + "'";
      String[] favorites_cols = new String[] { Audio.Playlists._ID };
      Uri favorites_uri = Audio.Playlists.EXTERNAL_CONTENT_URI;
      Cursor cursor = resolver.query(favorites_uri, favorites_cols, favorites_where, null,
          null);
      if (cursor.getCount() <= 0) {
        favorites_id = createPlaylist(context, PLAYLIST_NAME_FAVORITES);
      } else {
        cursor.moveToFirst();
        favorites_id = cursor.getLong(0);
        cursor.close();
      }

      String[] cols = new String[] { Playlists.Members.AUDIO_ID };
      Uri uri = Playlists.Members.getContentUri("external", favorites_id);
      Cursor cur = resolver.query(uri, cols, null, null, null);

      int base = cur.getCount();
      cur.moveToFirst();
      while (!cur.isAfterLast()) {
        if (cur.getLong(0) == id) return;
        cur.moveToNext();
      }
      cur.close();

      ContentValues values = new ContentValues();
      values.put(Playlists.Members.AUDIO_ID, id);
      values.put(Playlists.Members.PLAY_ORDER, base + 1);
      resolver.insert(uri, values);

    }
  }

  public static void addToPlaylist(Context context, long[] ids, long playlistid) {

    if (ids == null) {
      // this shouldn't happen (the menuitems shouldn't be visible
      // unless the selected item represents something playable
      Log.e("MusicBase", "ListSelection null");
    } else {
      int size = ids.length;
      ContentResolver resolver = context.getContentResolver();
      // need to determine the number of items currently in the playlist,
      // so the play_order field can be maintained.
      String[] cols = new String[] { "count(*)" };
      Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external", playlistid);
      Cursor cur = resolver.query(uri, cols, null, null, null);
      cur.moveToFirst();
      int base = cur.getInt(0);
      cur.close();
      int numinserted = 0;
      for (int i = 0; i < size; i += 1000) {
        makeInsertItems(ids, i, 1000, base);
        numinserted += resolver.bulkInsert(uri, sContentValuesCache);
      }
      String message = context.getResources().getQuantityString(
          R.plurals.NNNtrackstoplaylist, numinserted, numinserted);
      Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
      // mLastPlaylistSelected = playlistid;
    }
  }

  public static ServiceToken bindToService(Activity context) {

    return bindToService(context, null);
  }

  public static ServiceToken bindToService(Context context, ServiceConnection callback) {

    ContextWrapper cw = new ContextWrapper(context);
    cw.startService(new Intent(cw, MusicPlaybackService.class));
    ServiceBinder sb = new ServiceBinder(callback);
    if (cw.bindService(new Intent(cw, MusicPlaybackService.class), sb, 0)) {
      mConnectionMap.put(cw, sb);
      return new ServiceToken(cw);
    }
    Log.e("Music", "Failed to bind to service");
    return null;
  }

  public static void clearAlbumArtCache() {

    synchronized (mArtBitmapCache) {
      mArtBitmapCache.clear();
    }
  }

  public static void clearPlaylist(Context context, int plid) {

    Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external", plid);
    context.getContentResolver().delete(uri, null, null);
    return;
  }

  public static void clearQueue() {

    if (mService == null) return;

    try {
      mService.removeTracks(0, Integer.MAX_VALUE);
    } catch (RemoteException e) {
      e.printStackTrace();
    }
  }

  public static long createPlaylist(Context context, String name) {

    if (name != null && name.length() > 0) {
      ContentResolver resolver = context.getContentResolver();
      String[] cols = new String[] { MediaStore.Audio.Playlists.NAME };
      String whereclause = MediaStore.Audio.Playlists.NAME + " = '" + name + "'";
      Cursor cur = resolver.query(MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI, cols,
          whereclause, null, null);
      if (cur.getCount() <= 0) {
        ContentValues values = new ContentValues(1);
        values.put(MediaStore.Audio.Playlists.NAME, name);
        Uri uri = resolver.insert(MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI, values);
        return Long.parseLong(uri.getLastPathSegment());
      }
      return -1;
    }
    return -1;
  }

  public static void debugDump(PrintWriter out) {

    for (int i = 0; i < mMusicLog.length; i++) {
      int idx = mLogPtr + i;
      if (idx >= mMusicLog.length) {
        idx -= mMusicLog.length;
      }
      LogEntry entry = mMusicLog[idx];
      if (entry != null) {
        entry.dump(out);
      }
    }
  }

  public static void debugLog(Object o) {

    mMusicLog[mLogPtr] = new LogEntry(o);
    mLogPtr++;
    if (mLogPtr >= mMusicLog.length) {
      mLogPtr = 0;
    }
  }

  public static void deleteLyrics(Context context, long[] list) {

    String[] cols = new String[] { MediaStore.Audio.Media._ID, MediaStore.Audio.Media.DATA,
        MediaStore.Audio.Media.ALBUM_ID };
    StringBuilder where = new StringBuilder();
    where.append(MediaStore.Audio.Media._ID + " IN (");
    for (int i = 0; i < list.length; i++) {
      where.append(list[i]);
      if (i < list.length - 1) {
        where.append(",");
      }
    }
    where.append(")");
    Cursor c = query(context, MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, cols,
        where.toString(), null, null);

    int mDeletedLyricsCount = 0;

    if (c != null) {
      // remove files from card
      c.moveToFirst();
      while (!c.isAfterLast()) {
        String name = c.getString(1);
        String lyrics = name.substring(0, name.lastIndexOf(".")) + ".lrc";
        File f = new File(lyrics);
        try { // File.delete can throw a security exception
          if (!f.delete()) {
            // I'm not sure if we'd ever get here (deletion would
            // have to fail, but no exception thrown)
            Log.e(LOGTAG_MUSICUTILS, "Failed to delete file " + lyrics);
          } else {
            mDeletedLyricsCount += 1;
          }
          c.moveToNext();
        } catch (SecurityException ex) {
          c.moveToNext();
        }
      }
      c.close();
    }

    String message = context.getResources().getQuantityString(R.plurals.NNNlyricsdeleted,
        mDeletedLyricsCount, Integer.valueOf(mDeletedLyricsCount));

    reloadLyrics();
    Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
  }

  // XXX
  public static void deleteTracks(Context context, long[] list) {

    String[] cols = new String[] { MediaStore.Audio.Media._ID, MediaStore.Audio.Media.DATA,
        MediaStore.Audio.Media.ALBUM_ID };
    StringBuilder where = new StringBuilder();
    where.append(MediaStore.Audio.Media._ID + " IN (");
    for (int i = 0; i < list.length; i++) {
      where.append(list[i]);
      if (i < list.length - 1) {
        where.append(",");
      }
    }
    where.append(")");
    Cursor c = query(context, MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, cols,
        where.toString(), null, null);

    if (c != null) {

      // step 1: remove selected tracks from the current playlist, as well
      // as from the album art cache
      try {
        c.moveToFirst();
        while (!c.isAfterLast()) {
          // remove from current playlist
          long id = c.getLong(0);
          mService.removeTrack(id);
          // remove from album art cache
          long artIndex = c.getLong(2);
          synchronized (mArtBitmapCache) {
            mArtBitmapCache.remove(artIndex);
          }
          c.moveToNext();
        }
      } catch (RemoteException ex) {
      }

      // step 2: remove selected tracks from the database
      context.getContentResolver().delete(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
          where.toString(), null);

      // step 3: remove files from card
      c.moveToFirst();
      while (!c.isAfterLast()) {
        String name = c.getString(1);
        File f = new File(name);
        try { // File.delete can throw a security exception
          if (!f.delete()) {
            // I'm not sure if we'd ever get here (deletion would
            // have to fail, but no exception thrown)
            Log.e(LOGTAG_MUSICUTILS, "Failed to delete file " + name);
          }
          c.moveToNext();
        } catch (SecurityException ex) {
          c.moveToNext();
        }
      }
      c.close();
    }

    String message = context.getResources().getQuantityString(R.plurals.NNNtracksdeleted,
        list.length, Integer.valueOf(list.length));

    Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
    // We deleted a number of tracks, which could affect any number of
    // things
    // in the media content domain, so update everything.
    context.getContentResolver().notifyChange(Uri.parse("content://media"), null);
  }

  public static String getAlbumName(Context context, long album_id, boolean default_name) {
    String where = Audio.Albums._ID + "=" + album_id;
    String[] cols = new String[] { Audio.Albums.ALBUM };
    Uri uri = Audio.Albums.EXTERNAL_CONTENT_URI;
    Cursor cursor = context.getContentResolver().query(uri, cols, where, null, null);
    if (cursor.getCount() <= 0) {
      if (default_name)
        return context.getString(R.string.unknown_album);
      else
        return MediaStore.UNKNOWN_STRING;
    } else {
      cursor.moveToFirst();
      String name = cursor.getString(0);
      cursor.close();
      if (name == null || MediaStore.UNKNOWN_STRING.equals(name)) {
        if (default_name)
          return context.getString(R.string.unknown_album);
        else
          return MediaStore.UNKNOWN_STRING;
      }
      return name;
    }

  }

  public static long[] getAllSongs(Context context) {

    Cursor c = query(context, MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
        new String[] { MediaStore.Audio.Media._ID },
        MediaStore.Audio.Media.IS_MUSIC + "=1", null, null);
    try {
      if (c == null || c.getCount() == 0) return null;
      int len = c.getCount();
      long[] list = new long[len];
      for (int i = 0; i < len; i++) {
        c.moveToNext();
        list[i] = c.getLong(0);
      }

      return list;
    } finally {
      if (c != null) {
        c.close();
      }
    }
  }

  public static String getArtistName(Context context, long artist_id, boolean default_name) {
    String where = Audio.Artists._ID + "=" + artist_id;
    String[] cols = new String[] { Audio.Artists.ARTIST };
    Uri uri = Audio.Artists.EXTERNAL_CONTENT_URI;
    Cursor cursor = context.getContentResolver().query(uri, cols, where, null, null);
    if (cursor.getCount() <= 0) {
      if (default_name)
        return context.getString(R.string.unknown_artist);
      else
        return MediaStore.UNKNOWN_STRING;
    } else {
      cursor.moveToFirst();
      String name = cursor.getString(0);
      cursor.close();
      if (name == null || MediaStore.UNKNOWN_STRING.equals(name)) {
        if (default_name)
          return context.getString(R.string.unknown_artist);
        else
          return MediaStore.UNKNOWN_STRING;
      }
      return name;
    }

  }

  /**
   * Get album art for specified album. You should not pass in the album id
   * for the "unknown" album here (use -1 instead) This method always returns
   * the default album art icon when no album art is found.
   */
  public static Bitmap getArtwork(Context context, long song_id, long album_id) {

    return getArtwork(context, song_id, album_id, true);
  }

  /**
   * Get album art for specified album. You should not pass in the album id
   * for the "unknown" album here (use -1 instead)
   */
  public static Bitmap getArtwork(Context context, long song_id, long album_id,
      boolean allowdefault) {

    if (album_id < 0) {
      // This is something that is not in the database, so get the album
      // art directly
      // from the file.
      if (song_id >= 0) {
        Bitmap bm = getArtworkFromFile(context, song_id, -1);
        if (bm != null) return bm;
      }
      if (allowdefault) return getDefaultArtwork(context);
      return null;
    }

    ContentResolver res = context.getContentResolver();
    Uri uri = ContentUris.withAppendedId(mArtworkUri, album_id);
    if (uri != null) {
      InputStream in = null;
      try {
        in = res.openInputStream(uri);
        return BitmapFactory.decodeStream(in, null, mBitmapOptions);
      } catch (FileNotFoundException ex) {
        // The album art thumbnail does not actually exist. Maybe the
        // user deleted it, or
        // maybe it never existed to begin with.
        Bitmap bm = getArtworkFromFile(context, song_id, album_id);
        if (bm != null) {
          if (bm.getConfig() == null) {
            bm = bm.copy(Bitmap.Config.ARGB_8888, false);
            if (bm == null && allowdefault) return getDefaultArtwork(context);
          }
        } else if (allowdefault) {
          bm = getDefaultArtwork(context);
        }
        return bm;
      } finally {
        try {
          if (in != null) {
            in.close();
          }
        } catch (IOException ex) {
        }
      }
    }

    return null;
  }

  /**
   * Get album art for specified album. This method will not try to fall back
   * to getting artwork directly from the file, nor will it attempt to repair
   * the database.
   * 
   * @param context
   * @param album_id
   * @param w
   * @param h
   * @return
   */
  public static Bitmap getArtworkQuick(Context context, long album_id, int w, int h) {

    /*
     * NOTE: There is in fact a 1 pixel border on the right side in the
     * ImageView used to display this drawable. Take it into account now, so
     * we don't have to scale later.
     */

    w -= 1;
    ContentResolver res = context.getContentResolver();
    Uri uri = ContentUris.withAppendedId(mArtworkUri, album_id);
    if (uri != null) {
      ParcelFileDescriptor fd = null;
      try {
        fd = res.openFileDescriptor(uri, "r");
        int sampleSize = 1;

        // Compute the closest power-of-two scale factor
        // and pass that to mBitmapOptionsCache.inSampleSize, which will
        // result in faster decoding and better quality
        mBitmapOptionsCache.inJustDecodeBounds = true;
        BitmapFactory.decodeFileDescriptor(fd.getFileDescriptor(), null,
            mBitmapOptionsCache);
        int nextWidth = mBitmapOptionsCache.outWidth >> 1;
        int nextHeight = mBitmapOptionsCache.outHeight >> 1;
        while (nextWidth > w && nextHeight > h) {
          sampleSize <<= 1;
          nextWidth >>= 1;
          nextHeight >>= 1;
        }

        mBitmapOptionsCache.inSampleSize = sampleSize;
        mBitmapOptionsCache.inJustDecodeBounds = false;
        Bitmap b = BitmapFactory.decodeFileDescriptor(fd.getFileDescriptor(), null,
            mBitmapOptionsCache);

        if (b != null) {
          // finally rescale to exactly the size we need
          if (mBitmapOptionsCache.outWidth != w || mBitmapOptionsCache.outHeight != h) {

            int value = 0;
            if (b.getHeight() <= b.getWidth()) {
              value = b.getHeight();
            } else {
              value = b.getWidth();
            }

            Bitmap tmp = Bitmap.createBitmap(b, (b.getWidth() - value) / 2,
                (b.getHeight() - value) / 2, value, value);
            // Bitmap.createScaledBitmap() can return the same
            // bitmap
            if (tmp != b) {
              b.recycle();
            }
            b = tmp;
          }
        }

        return b;
      } catch (FileNotFoundException e) {
      } finally {
        try {
          if (fd != null) {
            fd.close();
          }
        } catch (IOException e) {
        }
      }
    }
    return null;
  }

  public static Uri getArtworkUri(Context context, long album_id) {
    return getArtworkUri(context, -1, album_id);
  }

  public static Uri getArtworkUri(Context context, long song_id, long album_id) {

    if (album_id < 0) {
      // This is something that is not in the database, so get the album
      // art directly
      // from the file.
      if (song_id >= 0) return getArtworkUriFromFile(context, song_id, -1);
      return null;
    }

    ContentResolver res = context.getContentResolver();
    Uri uri = ContentUris.withAppendedId(mArtworkUri, album_id);
    if (uri != null) {
      InputStream in = null;
      try {
        in = res.openInputStream(uri);
        return uri;
      } catch (FileNotFoundException ex) {
        // The album art thumbnail does not actually exist. Maybe the
        // user deleted it, or
        // maybe it never existed to begin with.
        return getArtworkUriFromFile(context, song_id, album_id);
      } finally {
        try {
          if (in != null) {
            in.close();
          }
        } catch (IOException ex) {
        }
      }
    }
    return null;
  }

  public static String getBetterGenresWhereClause(Context context) {

    StringBuilder builder = new StringBuilder();

    ContentResolver resolver = context.getContentResolver();
    String[] genres_cols = new String[] { Audio.Genres._ID };
    Uri genres_uri = Audio.Genres.EXTERNAL_CONTENT_URI;

    Cursor genres_cursor = resolver.query(genres_uri, genres_cols, null, null, null);

    if (genres_cursor != null) {
      if (genres_cursor.getCount() <= 0) {
        genres_cursor.close();
        return null;
      }
    } else
      return null;

    builder.append(Audio.Genres._ID + " IN (");
    genres_cursor.moveToFirst();
    while (!genres_cursor.isAfterLast()) {
      long genre_id = genres_cursor.getLong(0);
      StringBuilder where = new StringBuilder();
      where.append(Genres.Members.IS_MUSIC + "=1");
      where.append(" AND " + Genres.Members.TITLE + "!=''");
      String[] cols = new String[] { Genres.Members._ID };
      Uri uri = Genres.Members.getContentUri(EXTERNAL_VOLUME, genre_id);
      Cursor member_cursor = context.getContentResolver().query(uri, cols, where.toString(),
          null, null);
      if (member_cursor != null) {
        if (member_cursor.getCount() > 0) {
          builder.append(genre_id + ",");
        }
        member_cursor.close();
      }
      genres_cursor.moveToNext();
    }
    genres_cursor.close();
    builder.deleteCharAt(builder.length() - 1);
    builder.append(")");

    return builder.toString();
  }

  public static Drawable getCachedArtwork(Context context, long index,
      BitmapDrawable defaultArtwork) {
    Drawable d = null;
    synchronized (mArtCache) {
      d = mArtCache.get(index);
    }
    if (d == null) {
      d = defaultArtwork;
      final Bitmap icon = defaultArtwork.getBitmap();
      int w = icon.getWidth();
      int h = icon.getHeight();
      Bitmap b = MusicUtils.getArtworkQuick(context, index, w, h);
      if (b != null) {
        d = new BitmapDrawable(b);
        synchronized (mArtCache) {
          // the cache may have changed since we checked
          Drawable value = mArtCache.get(index);
          if (value == null) {
            mArtCache.put(index, d);
          } else {
            d = value;
          }
        }
      }
    }
    return d;
  }

  public static Drawable getCachedArtwork(Context context, long index, int width, int height) {
    Bitmap b = MusicUtils.getArtworkQuick(context, index, width, height);
    return new FastBitmapDrawable(b);
  }

  public static Bitmap getCachedArtworkBitmap(Context context, long index, int width, int height) {

    Bitmap art = null;
    synchronized (mArtBitmapCache) {
      art = mArtBitmapCache.get(index);
    }
    if (art == null) {
      art = MusicUtils.getArtworkQuick(context, index, width, height);
      if (art != null) {
        synchronized (mArtBitmapCache) {
          mArtBitmapCache.put(index, art);
        }
      }
    }
    return art;
  }

  public static int getCardId(Context context) {

    ContentResolver res = context.getContentResolver();
    Cursor c = res.query(Uri.parse("content://media/external/fs_id"), null, null, null, null);
    int id = -1;
    if (c != null) {
      c.moveToFirst();
      id = c.getInt(0);
      c.close();
    }
    return id;
  }

  public static long getCurrentAlbumId() {

    if (mService != null) {
      try {
        return mService.getAlbumId();
      } catch (RemoteException ex) {
      }
    }
    return -1;
  }

  public static long getCurrentArtistId() {

    if (MusicUtils.mService != null) {
      try {
        return mService.getArtistId();
      } catch (RemoteException ex) {
      }
    }
    return -1;
  }

  public static long getCurrentAudioId() {

    if (MusicUtils.mService != null) {
      try {
        return mService.getAudioId();
      } catch (RemoteException ex) {
      }
    }
    return -1;
  }

  public static int getCurrentShuffleMode() {

    int mode = SHUFFLE_NONE;
    if (mService != null) {
      try {
        mode = mService.getShuffleMode();
      } catch (RemoteException ex) {
      }
    }
    return mode;
  }

  public static long getFavoritesId(Context context) {
    long favorites_id = -1;
    String favorites_where = Audio.Playlists.NAME + "='" + PLAYLIST_NAME_FAVORITES + "'";
    String[] favorites_cols = new String[] { Audio.Playlists._ID };
    Uri favorites_uri = Audio.Playlists.EXTERNAL_CONTENT_URI;
    Cursor cursor = query(context, favorites_uri, favorites_cols, favorites_where, null, null);
    if (cursor.getCount() <= 0) {
      favorites_id = createPlaylist(context, PLAYLIST_NAME_FAVORITES);
    } else {
      cursor.moveToFirst();
      favorites_id = cursor.getLong(0);
      cursor.close();
    }
    return favorites_id;
  }

  public static String getGenreName(Context context, long genre_id, boolean default_name) {
    String where = Audio.Genres._ID + "=" + genre_id;
    String[] cols = new String[] { Audio.Genres.NAME };
    Uri uri = Audio.Genres.EXTERNAL_CONTENT_URI;
    Cursor cursor = context.getContentResolver().query(uri, cols, where, null, null);
    if (cursor.getCount() <= 0) {
      if (default_name)
        return context.getString(R.string.unknown_genre);
      else
        return MediaStore.UNKNOWN_STRING;
    } else {
      cursor.moveToFirst();
      String name = cursor.getString(0);
      cursor.close();
      if (name == null || MediaStore.UNKNOWN_STRING.equals(name)) {
        if (default_name)
          return context.getString(R.string.unknown_genre);
        else
          return MediaStore.UNKNOWN_STRING;
      }
      return name;
    }
  }

  public static String getPlaylistName(Context context, long playlist_id) {
    String where = Audio.Playlists._ID + "=" + playlist_id;
    String[] cols = new String[] { Audio.Playlists.NAME };
    Uri uri = Audio.Playlists.EXTERNAL_CONTENT_URI;
    Cursor cursor = context.getContentResolver().query(uri, cols, where, null, null);
    if (cursor.getCount() <= 0) return "";

    cursor.moveToFirst();
    String name = cursor.getString(0);
    cursor.close();
    return name;
  }

  public static long[] getQueue() {

    if (mService == null) return mEmptyList;

    try {
      return mService.getQueue();
    } catch (RemoteException e) {
      e.printStackTrace();
    }
    return mEmptyList;
  }

  public static int getQueuePosition() {
    if (mService == null) return 0;

    try {
      return mService.getQueuePosition();
    } catch (RemoteException e) {
      e.printStackTrace();
    }
    return 0;
  }

  public static long getSleepTimerRemained() {

    long remained = 0;
    if (mService == null) return remained;
    try {
      remained = mService.getSleepTimerRemained();
    } catch (Exception e) {
      // do nothing
    }
    return remained;
  }

  public static long[] getSongListForAlbum(Context context, long id) {

    final String[] ccols = new String[] { MediaStore.Audio.Media._ID };
    String where = MediaStore.Audio.Media.ALBUM_ID + "=" + id + " AND "
        + MediaStore.Audio.Media.IS_MUSIC + "=1";
    Cursor cursor = query(context, MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, ccols, where,
        null, MediaStore.Audio.Media.TRACK);

    if (cursor != null) {
      long[] list = getSongListForCursor(cursor);
      cursor.close();
      return list;
    }
    return mEmptyList;
  }

  public static long[] getSongListForArtist(Context context, long id) {

    final String[] ccols = new String[] { MediaStore.Audio.Media._ID };
    String where = MediaStore.Audio.Media.ARTIST_ID + "=" + id + " AND "
        + MediaStore.Audio.Media.IS_MUSIC + "=1";
    Cursor cursor = query(context, MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, ccols, where,
        null, MediaStore.Audio.Media.ALBUM_KEY + "," + MediaStore.Audio.Media.TRACK);

    if (cursor != null) {
      long[] list = getSongListForCursor(cursor);
      cursor.close();
      return list;
    }
    return mEmptyList;
  }

  public static long[] getSongListForCursor(Cursor cursor) {

    if (cursor == null) return mEmptyList;
    int len = cursor.getCount();
    long[] list = new long[len];
    cursor.moveToFirst();
    int colidx = -1;
    try {
      colidx = cursor.getColumnIndexOrThrow(MediaStore.Audio.Playlists.Members.AUDIO_ID);
    } catch (IllegalArgumentException ex) {
      colidx = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media._ID);
    }
    for (int i = 0; i < len; i++) {
      list[i] = cursor.getLong(colidx);
      cursor.moveToNext();
    }
    return list;
  }

  public static long[] getSongListForPlaylist(Context context, long plid) {

    final String[] ccols = new String[] { MediaStore.Audio.Playlists.Members.AUDIO_ID };
    Cursor cursor = query(context, Playlists.Members.getContentUri("external", plid), ccols,
        null, null, Playlists.Members.DEFAULT_SORT_ORDER);

    if (cursor != null) {
      long[] list = getSongListForCursor(cursor);
      cursor.close();
      return list;
    }
    return mEmptyList;
  }

  public static String getTrackName(Context context, long audio_id) {
    String where = Audio.Media._ID + "=" + audio_id;
    String[] cols = new String[] { Audio.Media.TITLE };
    Uri uri = Audio.Media.EXTERNAL_CONTENT_URI;
    Cursor cursor = context.getContentResolver().query(uri, cols, where, null, null);
    if (cursor.getCount() <= 0) return "";

    cursor.moveToFirst();
    String name = cursor.getString(0);
    cursor.close();
    return name;
  }

  public static void initAlbumArtCache() {

    try {
      int id = mService.getMediaMountedCount();
      if (id != mArtCacheId) {
        clearAlbumArtCache();
        mArtCacheId = id;
      }
    } catch (RemoteException e) {
      e.printStackTrace();
    }
  }

  public static boolean isFavorite(Context context, long id) {

    long favorites_id;

    if (id < 0) {
      // this shouldn't happen (the menuitems shouldn't be visible
      // unless the selected item represents something playable
      Log.e(LOGTAG_MUSICUTILS, "playlist id " + id + " is invalid.");
    } else {
      ContentResolver resolver = context.getContentResolver();
      // need to determine the number of items currently in the playlist,
      // so the play_order field can be maintained.

      String favorites_where = Audio.Playlists.NAME + "='" + PLAYLIST_NAME_FAVORITES + "'";
      String[] favorites_cols = new String[] { Audio.Playlists._ID };
      Uri favorites_uri = Audio.Playlists.EXTERNAL_CONTENT_URI;
      Cursor cursor = resolver.query(favorites_uri, favorites_cols, favorites_where, null,
          null);
      if (cursor.getCount() <= 0) {
        favorites_id = createPlaylist(context, PLAYLIST_NAME_FAVORITES);
      } else {
        cursor.moveToFirst();
        favorites_id = cursor.getLong(0);
        cursor.close();
      }

      String[] cols = new String[] { Playlists.Members.AUDIO_ID };
      Uri uri = Playlists.Members.getContentUri("external", favorites_id);
      Cursor cur = resolver.query(uri, cols, null, null, null);

      cur.moveToFirst();
      while (!cur.isAfterLast()) {
        if (cur.getLong(0) == id) {
          cur.close();
          return true;
        }
        cur.moveToNext();
      }
      cur.close();
      return false;
    }
    return false;
  }

  public static boolean isMediaScannerScanning(Context context) {

    boolean result = false;
    Cursor cursor = query(context, MediaStore.getMediaScannerUri(),
        new String[] { MediaStore.MEDIA_SCANNER_VOLUME }, null, null, null);
    if (cursor != null) {
      if (cursor.getCount() == 1) {
        cursor.moveToFirst();
        result = "external".equals(cursor.getString(0));
      }
      cursor.close();
    }

    return result;
  }

  /*
   * Returns true if a file is currently opened for playback (regardless of
   * whether it's playing or paused).
   */
  public static boolean isMusicLoaded() {

    if (MusicUtils.mService != null) {
      try {
        return mService.getPath() != null;
      } catch (RemoteException ex) {
      }
    }
    return false;
  }

  public static String makeAlbumsLabel(Context context, int numalbums, int numsongs,
      boolean isUnknown) {

    // There are two formats for the albums/songs information:
    // "N Song(s)" - used for unknown artist/album
    // "N Album(s)" - used for known albums

    StringBuilder songs_albums = new StringBuilder();

    Resources r = context.getResources();
    if (isUnknown) {
      String f = r.getQuantityText(R.plurals.Nsongs, numsongs).toString();
      sFormatBuilder.setLength(0);
      sFormatter.format(f, Integer.valueOf(numsongs));
      songs_albums.append(sFormatBuilder);
    } else {
      String f = r.getQuantityText(R.plurals.Nalbums, numalbums).toString();
      sFormatBuilder.setLength(0);
      sFormatter.format(f, Integer.valueOf(numalbums));
      songs_albums.append(sFormatBuilder);
      songs_albums.append("\n");
    }
    return songs_albums.toString();
  }

  /**
   * This is now only used for the query screen
   */
  public static String makeAlbumsSongsLabel(Context context, int numalbums, int numsongs,
      boolean isUnknown) {

    // There are several formats for the albums/songs information:
    // "1 Song" - used if there is only 1 song
    // "N Songs" - used for the "unknown artist" item
    // "1 Album"/"N Songs"
    // "N Album"/"M Songs"
    // Depending on locale, these may need to be further subdivided

    StringBuilder songs_albums = new StringBuilder();

    Resources r = context.getResources();
    if (!isUnknown) {
      String f = r.getQuantityText(R.plurals.Nalbums, numalbums).toString();
      sFormatBuilder.setLength(0);
      sFormatter.format(f, Integer.valueOf(numalbums));
      songs_albums.append(sFormatBuilder);
      songs_albums.append("\n");
    }
    String f = r.getQuantityText(R.plurals.Nsongs, numsongs).toString();
    sFormatBuilder.setLength(0);
    sFormatter.format(f, Integer.valueOf(numsongs));
    songs_albums.append(sFormatBuilder);
    return songs_albums.toString();
  }

  public static void makePlaylistList(Context context, boolean create_shortcut,
      List<Map<String, String>> list) {

    Map<String, String> map;

    String[] cols = new String[] { Audio.Playlists._ID, Audio.Playlists.NAME };
    StringBuilder where = new StringBuilder();

    ContentResolver resolver = context.getContentResolver();
    if (resolver == null) {
      System.out.println("resolver = null");
    } else {
      where.append(Audio.Playlists.NAME + " != ''");
      where.append(" AND " + Audio.Playlists.NAME + " != '" + PLAYLIST_NAME_FAVORITES + "'");
      Cursor cur = resolver.query(Audio.Playlists.EXTERNAL_CONTENT_URI, cols,
          where.toString(), null, Audio.Playlists.NAME);
      list.clear();

      map = new HashMap<String, String>();
      map.put(MAP_KEY_ID, String.valueOf(PLAYLIST_FAVORITES));
      map.put(MAP_KEY_NAME, context.getString(R.string.favorites));
      list.add(map);

      if (create_shortcut) {
        map = new HashMap<String, String>();
        map.put(MAP_KEY_ID, String.valueOf(PLAYLIST_ALL_SONGS));
        map.put(MAP_KEY_NAME, context.getString(R.string.play_all));
        list.add(map);

        map = new HashMap<String, String>();
        map.put(MAP_KEY_ID, String.valueOf(PLAYLIST_RECENTLY_ADDED));
        map.put(MAP_KEY_NAME, context.getString(R.string.recently_added));
        list.add(map);
      } else {
        map = new HashMap<String, String>();
        map.put(MAP_KEY_ID, String.valueOf(PLAYLIST_QUEUE));
        map.put(MAP_KEY_NAME, context.getString(R.string.queue));
        list.add(map);

        map = new HashMap<String, String>();
        map.put(MAP_KEY_ID, String.valueOf(PLAYLIST_NEW));
        map.put(MAP_KEY_NAME, context.getString(R.string.new_playlist));
        list.add(map);
      }

      if (cur != null && cur.getCount() > 0) {
        cur.moveToFirst();
        while (!cur.isAfterLast()) {
          map = new HashMap<String, String>();
          map.put(MAP_KEY_ID, String.valueOf(cur.getLong(0)));
          map.put(MAP_KEY_NAME, cur.getString(1));
          list.add(map);
          cur.moveToNext();
        }

      }
      if (cur != null) {
        cur.close();
      }
    }
  }

  public static String makeTimeString(Context context, long secs) {

    String durationformat = context.getString(secs < 3600 ? R.string.durationformatshort
        : R.string.durationformatlong);

    /*
     * Provide multiple arguments so the format can be changed easily by
     * modifying the xml.
     */
    sFormatBuilder.setLength(0);

    final Object[] timeArgs = sTimeArgs;
    timeArgs[0] = secs / 3600;
    timeArgs[1] = secs / 60;
    timeArgs[2] = secs / 60 % 60;
    timeArgs[3] = secs;
    timeArgs[4] = secs % 60;

    return sFormatter.format(durationformat, timeArgs).toString();
  }

  public static void movePlaylistItem(Context context, Cursor cursor, long playlist_id, int from,
      int to) {

    if (from < 0) {
      from = 0;
    }
    if (to < 0) {
      to = 0;
    }

    ContentResolver resolver = context.getContentResolver();
    cursor.moveToPosition(from);
    long id = cursor.getLong(cursor.getColumnIndexOrThrow(Playlists.Members.AUDIO_ID));
    Uri uri = Playlists.Members.getContentUri("external", playlist_id);
    resolver.delete(uri, Playlists.Members.AUDIO_ID + "=" + id, null);

    ContentValues values = new ContentValues();
    values.put(Playlists.Members.AUDIO_ID, id);
    values.put(Playlists.Members.PLAY_ORDER, to);
    resolver.insert(uri, values);
  }

  public static void moveQueueItem(int from, int to) {
    if (mService == null) return;

    try {
      mService.moveQueueItem(from, to);
    } catch (RemoteException e) {
      e.printStackTrace();
    }
  }

  public static String parseGenreName(String orig) {
    int genre_id = -1;

    if (orig == null || orig.trim().length() <= 0) return "Unknown";

    try {
      genre_id = Integer.parseInt(orig);
    } catch (NumberFormatException e) {
      // string is not a valid number, so return original value.
      return orig;
    }
    if (genre_id >= 0 && genre_id < GENRES_DB.length)
      return GENRES_DB[genre_id];
    else
      return "Unknown";

  }

  public static void playAll(Context context) {

    playAll(context, getAllSongs(context), 0);
  }

  public static void playAll(Context context, Cursor cursor) {

    playAll(context, cursor, 0, false);
  }

  public static void playAll(Context context, Cursor cursor, int position) {

    playAll(context, cursor, position, false);
  }

  public static void playAll(Context context, long[] list, int position) {

    playAll(context, list, position, false);
  }

  public static void playPlaylist(Context context, long plid) {

    long[] list = getSongListForPlaylist(context, plid);
    if (list != null) {
      playAll(context, list, -1, false);
    }
  }

  public static void playRecentlyAdded(Context context) {

    // do a query for all songs added in the last X weeks
    int weekX = new PreferencesEditor(context).getIntPref(PREF_KEY_NUMWEEKS, 2) * 3600 * 24 * 7;
    final String[] ccols = new String[] { MediaStore.Audio.Media._ID };
    String where = MediaStore.MediaColumns.DATE_ADDED + ">"
        + (System.currentTimeMillis() / 1000 - weekX);
    Cursor cursor = query(context, MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, ccols, where,
        null, MediaStore.Audio.Media.DEFAULT_SORT_ORDER);

    if (cursor == null) // Todo: show a message
      return;
    try {
      int len = cursor.getCount();
      long[] list = new long[len];
      for (int i = 0; i < len; i++) {
        cursor.moveToNext();
        list[i] = cursor.getLong(0);
      }
      MusicUtils.playAll(context, list, 0);
    } catch (SQLiteException ex) {
    } finally {
      cursor.close();
    }
  }

  public static Cursor query(Context context, Uri uri, String[] projection, String selection,
      String[] selectionArgs, String sortOrder) {

    return query(context, uri, projection, selection, selectionArgs, sortOrder, 0);
  }

  public static Cursor query(Context context, Uri uri, String[] projection, String selection,
      String[] selectionArgs, String sortOrder, int limit) {

    try {
      ContentResolver resolver = context.getContentResolver();
      if (resolver == null) return null;
      if (limit > 0) {
        uri = uri.buildUpon().appendQueryParameter("limit", "" + limit).build();
      }
      return resolver.query(uri, projection, selection, selectionArgs, sortOrder);
    } catch (UnsupportedOperationException ex) {
      return null;
    }

  }

  public static void reloadLyrics() {

    if (mService == null) return;
    try {
      mService.reloadLyrics();
    } catch (Exception e) {
      // e.printStackTrace();
    }
  }

  public static void reloadSettings() {

    if (mService == null) return;
    try {
      mService.reloadSettings();
    } catch (Exception e) {
      // e.printStackTrace();
    }
  }

  public static void removeFromFavorites(Context context, long id) {

    long favorites_id;

    if (id < 0) {
      // this shouldn't happen (the menuitems shouldn't be visible
      // unless the selected item represents something playable
      Log.e(LOGTAG_MUSICUTILS, "playlist id " + id + " is invalid.");
    } else {
      ContentResolver resolver = context.getContentResolver();
      // need to determine the number of items currently in the playlist,
      // so the play_order field can be maintained.

      String favorites_where = Audio.Playlists.NAME + "='" + PLAYLIST_NAME_FAVORITES + "'";
      String[] favorites_cols = new String[] { Audio.Playlists._ID };
      Uri favorites_uri = Audio.Playlists.EXTERNAL_CONTENT_URI;
      Cursor cursor = resolver.query(favorites_uri, favorites_cols, favorites_where, null,
          null);
      if (cursor.getCount() <= 0) {
        favorites_id = createPlaylist(context, PLAYLIST_NAME_FAVORITES);
      } else {
        cursor.moveToFirst();
        favorites_id = cursor.getLong(0);
        cursor.close();
      }

      Uri uri = Playlists.Members.getContentUri("external", favorites_id);
      resolver.delete(uri, Playlists.Members.AUDIO_ID + "=" + id, null);

    }
  }

  public static int removeTrack(long id) {
    if (mService == null) return 0;

    try {
      return mService.removeTrack(id);
    } catch (RemoteException e) {
      e.printStackTrace();
    }
    return 0;
  }

  public static int removeTracks(int first, int last) {
    if (mService == null) return 0;

    try {
      return mService.removeTracks(first, last);
    } catch (RemoteException e) {
      e.printStackTrace();
    }
    return 0;
  }

  public static void renamePlaylist(Context context, long id, String name) {

    if (name != null && name.length() > 0) {
      ContentResolver resolver = context.getContentResolver();
      ContentValues values = new ContentValues(1);
      values.put(MediaStore.Audio.Playlists.NAME, name);
      resolver.update(MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI, values,
          MediaStore.Audio.Playlists._ID + "=?", new String[] { String.valueOf(id) });

      Toast.makeText(context, R.string.playlist_renamed, Toast.LENGTH_SHORT).show();
    }
  }

  public static void setBackground(View v, Bitmap bm) {

    if (bm == null) {
      v.setBackgroundResource(0);
      return;
    }

    int vwidth = v.getWidth();
    int vheight = v.getHeight();
    int bwidth = bm.getWidth();
    int bheight = bm.getHeight();
    float scalex = (float) vwidth / bwidth;
    float scaley = (float) vheight / bheight;
    float scale = Math.max(scalex, scaley) * 1.3f;

    Bitmap.Config config = Bitmap.Config.ARGB_8888;
    Bitmap bg = Bitmap.createBitmap(vwidth, vheight, config);
    Canvas c = new Canvas(bg);
    Paint paint = new Paint();
    paint.setAntiAlias(true);
    paint.setFilterBitmap(true);
    ColorMatrix greymatrix = new ColorMatrix();
    greymatrix.setSaturation(0);
    ColorMatrix darkmatrix = new ColorMatrix();
    darkmatrix.setScale(.3f, .3f, .3f, 1.0f);
    greymatrix.postConcat(darkmatrix);
    ColorFilter filter = new ColorMatrixColorFilter(greymatrix);
    paint.setColorFilter(filter);
    Matrix matrix = new Matrix();
    matrix.setTranslate(-bwidth / 2, -bheight / 2); // move bitmap center to
                            // origin
    matrix.postRotate(10);
    matrix.postScale(scale, scale);
    matrix.postTranslate(vwidth / 2, vheight / 2); // Move bitmap center to
                            // view center
    c.drawBitmap(bm, matrix, paint);
    v.setBackgroundDrawable(new BitmapDrawable(bg));
  }

  public static void setQueueId(long id) {
    if (mService == null) return;
    try {
      mService.setQueueId(id);
    } catch (RemoteException e) {
      e.printStackTrace();
    }
  }

  public static void setQueuePosition(int index) {
    if (mService == null) return;
    try {
      mService.setQueuePosition(index);
    } catch (RemoteException e) {
      e.printStackTrace();
    }
  }

  public static void setSpinnerState(Activity a) {

    if (isMediaScannerScanning(a)) {
      // start the progress spinner
      a.getWindow().setFeatureInt(Window.FEATURE_INDETERMINATE_PROGRESS,
          Window.PROGRESS_INDETERMINATE_ON);

      a.getWindow().setFeatureInt(Window.FEATURE_INDETERMINATE_PROGRESS,
          Window.PROGRESS_VISIBILITY_ON);
    } else {
      // stop the progress spinner
      a.getWindow().setFeatureInt(Window.FEATURE_INDETERMINATE_PROGRESS,
          Window.PROGRESS_VISIBILITY_OFF);
    }
  }

  public static void shuffleAll(Context context) {

    playAll(context, getAllSongs(context), 0, true);
  }

  public static void shuffleAll(Context context, Cursor cursor) {

    playAll(context, cursor, 0, true);
  }

  public static void startSleepTimer(long milliseconds, boolean gentle) {

    if (mService == null) return;
    try {
      mService.startSleepTimer(milliseconds, gentle);
    } catch (Exception e) {
      // do nothing
    }
  }

  public static void stopSleepTimer() {

    if (mService == null) return;
    try {
      mService.stopSleepTimer();
    } catch (Exception e) {
      // do nothing
    }
  }

  public static void unbindFromService(ServiceToken token) {

    if (token == null) {
      Log.e(LOGTAG_MUSICUTILS, "Trying to unbind with null token");
      return;
    }
    ContextWrapper wrapper = token.mWrappedContext;
    ServiceBinder binder = mConnectionMap.remove(wrapper);
    if (binder == null) {
      Log.e(LOGTAG_MUSICUTILS, "Trying to unbind for unknown Context");
      return;
    }
    wrapper.unbindService(binder);
    if (mConnectionMap.isEmpty()) {
      // presumably there is nobody interested in the service at this
      // point,
      // so don't hang on to the ServiceConnection
      mService = null;
    }
  }

  /** get album art for specified file */
  private static Bitmap getArtworkFromFile(Context context, long songid, long albumid) {

    Bitmap bm = null;

    if (albumid < 0 && songid < 0)
      throw new IllegalArgumentException("Must specify an album or a song id");

    try {
      if (albumid < 0) {
        Uri uri = Uri.parse("content://media/external/audio/media/" + songid + "/albumart");
        ParcelFileDescriptor pfd = context.getContentResolver()
            .openFileDescriptor(uri, "r");
        if (pfd != null) {
          FileDescriptor fd = pfd.getFileDescriptor();
          bm = BitmapFactory.decodeFileDescriptor(fd);
        }
      } else {
        Uri uri = ContentUris.withAppendedId(mArtworkUri, albumid);
        ParcelFileDescriptor pfd = context.getContentResolver()
            .openFileDescriptor(uri, "r");
        if (pfd != null) {
          FileDescriptor fd = pfd.getFileDescriptor();
          bm = BitmapFactory.decodeFileDescriptor(fd);
        }
      }
    } catch (IllegalStateException ex) {
    } catch (FileNotFoundException ex) {
    }
    return bm;
  }

  private static Uri getArtworkUriFromFile(Context context, long songid, long albumid) {

    if (albumid < 0 && songid < 0) return null;

    try {
      if (albumid < 0) {
        Uri uri = Uri.parse("content://media/external/audio/media/" + songid + "/albumart");
        ParcelFileDescriptor pfd = context.getContentResolver()
            .openFileDescriptor(uri, "r");
        if (pfd != null) return uri;
      } else {
        Uri uri = ContentUris.withAppendedId(mArtworkUri, albumid);
        ParcelFileDescriptor pfd = context.getContentResolver()
            .openFileDescriptor(uri, "r");
        if (pfd != null) return uri;
      }
    } catch (FileNotFoundException ex) {
      //
    }
    return null;
  }

  private static Bitmap getDefaultArtwork(Context context) {

    BitmapFactory.Options opts = new BitmapFactory.Options();
    opts.inPreferredConfig = Bitmap.Config.ARGB_8888;
    return BitmapFactory.decodeStream(
        context.getResources().openRawResource(R.drawable.ic_mp_albumart_unknown), null,
        opts);
  }

  /**
   * @param ids
   *            The source array containing all the ids to be added to the
   *            playlist
   * @param offset
   *            Where in the 'ids' array we start reading
   * @param len
   *            How many items to copy during this pass
   * @param base
   *            The play order offset to use for this pass
   */
  private static void makeInsertItems(long[] ids, int offset, int len, int base) {

    // adjust 'len' if would extend beyond the end of the source array
    if (offset + len > ids.length) {
      len = ids.length - offset;
    }
    // allocate the ContentValues array, or reallocate if it is the wrong
    // size
    if (sContentValuesCache == null || sContentValuesCache.length != len) {
      sContentValuesCache = new ContentValues[len];
    }
    // fill in the ContentValues array with the right values for this pass
    for (int i = 0; i < len; i++) {
      if (sContentValuesCache[i] == null) {
        sContentValuesCache[i] = new ContentValues();
      }

      sContentValuesCache[i].put(Playlists.Members.PLAY_ORDER, base + offset + i);
      sContentValuesCache[i].put(Playlists.Members.AUDIO_ID, ids[offset + i]);
    }
  }

  private static void playAll(Context context, Cursor cursor, int position, boolean force_shuffle) {

    long[] list = getSongListForCursor(cursor);
    playAll(context, list, position, force_shuffle);
  }

  private static void playAll(Context context, long[] list, int position, boolean force_shuffle) {

    if (list == null || list.length == 0 || mService == null) {
      Log.d(LOGTAG_MUSICUTILS, "attempt to play empty song list");
      // Don't try to play empty playlists. Nothing good will come of it.
      Toast.makeText(context, R.string.emptyplaylist, Toast.LENGTH_SHORT).show();
      return;
    }
    try {
      if (force_shuffle) {
        mService.setShuffleMode(SHUFFLE_NORMAL);
      }
      long curid = mService.getAudioId();
      int curpos = mService.getQueuePosition();
      if (position != -1 && curpos == position && curid == list[position]) {
        // The selected file is the file that's currently playing;
        // figure out if we need to restart with a new playlist,
        // or just launch the playback activity.
        long[] playlist = mService.getQueue();
        if (Arrays.equals(list, playlist)) {
          // we don't need to set a new list, but we should resume
          // playback if needed
          mService.play();
          return; // the 'finally' block will still run
        }
      }
      if (position < 0) {
        position = 0;
      }
      mService.open(list, force_shuffle ? -1 : position);
      mService.play();
    } catch (RemoteException ex) {
    } finally {
      Intent intent = new Intent(INTENT_PLAYBACK_VIEWER)
          .setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
      context.startActivity(intent);
    }
  }

  static protected Uri getContentURIForPath(String path) {

    return Uri.fromFile(new File(path));
  }

  // A really simple BitmapDrawable-like class, that doesn't do
  // scaling, dithering or filtering.
  private static class FastBitmapDrawable extends Drawable {

    private Bitmap mBitmap;

    public FastBitmapDrawable(Bitmap b) {
      mBitmap = b;
    }

    @Override
    public void draw(Canvas canvas) {
      if (mBitmap == null) return;
      canvas.drawBitmap(mBitmap, 0, 0, null);
    }

    @Override
    public int getOpacity() {
      return PixelFormat.OPAQUE;
    }

    @Override
    public void setAlpha(int alpha) {
    }

    @Override
    public void setColorFilter(ColorFilter cf) {
    }
  }

  private static class ServiceBinder implements ServiceConnection {

    ServiceConnection mCallback;

    ServiceBinder(ServiceConnection callback) {

      mCallback = callback;
    }

    @Override
    public void onServiceConnected(ComponentName className, android.os.IBinder service) {

      mService = IMusicPlaybackService.Stub.asInterface(service);
      initAlbumArtCache();
      if (mCallback != null) {
        mCallback.onServiceConnected(className, service);
      }
    }

    @Override
    public void onServiceDisconnected(ComponentName className) {

      if (mCallback != null) {
        mCallback.onServiceDisconnected(className);
      }
      mService = null;
    }
  }

  static class LogEntry {

    Object item;
    long time;

    LogEntry(Object o) {

      item = o;
      time = System.currentTimeMillis();
    }

    void dump(PrintWriter out) {

      mTime.set(time);
      out.print(mTime.toString() + " : ");
      if (item instanceof Exception) {
        ((Exception) item).printStackTrace(out);
      } else {
        out.println(item);
      }
    }
  }
}




Java Source Code List

org.yammp.Constants.java
org.yammp.MediaAppWidgetProvider4x1.java
org.yammp.MediaAppWidgetProvider4x2.java
org.yammp.MediaButtonIntentReceiver.java
org.yammp.MusicPlaybackService.java
org.yammp.app.AlbumFragment.java
org.yammp.app.AppearanceSettingsActivity.java
org.yammp.app.ArtistFragment.java
org.yammp.app.Equalizer.java
org.yammp.app.GenreFragment.java
org.yammp.app.LyricsFragment.java
org.yammp.app.MusicBrowserActivity.java
org.yammp.app.MusicBrowserFragment.java
org.yammp.app.MusicPlaybackActivity.java
org.yammp.app.MusicSettingsActivity.java
org.yammp.app.PlaylistFragment.java
org.yammp.app.PluginFragment.java
org.yammp.app.PluginsManagerActivity.java
org.yammp.app.QueryBrowserActivity.java
org.yammp.app.QueryFragment.java
org.yammp.app.TrackBrowserActivity.java
org.yammp.app.TrackFragment.java
org.yammp.dialog.DeleteDialog.java
org.yammp.dialog.PlayShortcut.java
org.yammp.dialog.PlaylistDialog.java
org.yammp.dialog.PlaylistPickerDialog.java
org.yammp.dialog.PlaylistPicker.java
org.yammp.dialog.ScanningProgress.java
org.yammp.dialog.SearchDialog.java
org.yammp.dialog.SleepTimerDialog.java
org.yammp.dialog.VerticalTextSpinnerDialog.java
org.yammp.dialog.WeekSelector.java
org.yammp.util.ColorAnalyser.java
org.yammp.util.EqualizerWrapper.java
org.yammp.util.ImageDownloader.java
org.yammp.util.LazyImageLoader.java
org.yammp.util.LyricsDownloader.java
org.yammp.util.LyricsParser.java
org.yammp.util.LyricsSplitter.java
org.yammp.util.MusicUtils.java
org.yammp.util.PreferencesEditor.java
org.yammp.util.ServiceToken.java
org.yammp.util.ShakeListener.java
org.yammp.util.SortCursor.java
org.yammp.util.VisualizerCompatAudioFX.java
org.yammp.util.VisualizerCompatScoop.java
org.yammp.util.VisualizerCompat.java
org.yammp.util.VisualizerWrapper.java
org.yammp.view.EqualizerView.java
org.yammp.view.SliderView.java
org.yammp.view.TouchPaintView.java
org.yammp.view.VerticalTextSpinner.java
org.yammp.view.VisualizerViewFftSpectrum.java
org.yammp.view.VisualizerViewWaveForm.java
org.yammp.widget.CheckableRelativeLayout.java
org.yammp.widget.RepeatingImageButton.java
org.yammp.widget.SeparatedListAdapter.java
org.yammp.widget.TextScrollView.java
org.yammp.widget.TouchInterceptor.java