Rework MediaAdapter to be backed by a Cursor instead of an array

This reduces memory requirements and amount of code
This commit is contained in:
Christopher Eby 2010-04-03 10:05:13 -05:00
parent 0571a3189c
commit e21e1c6532
5 changed files with 217 additions and 476 deletions

View File

@ -18,50 +18,121 @@
package org.kreed.vanilla;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.net.Uri;
import android.provider.BaseColumns;
import android.provider.MediaStore;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.BaseAdapter;
import android.widget.CursorAdapter;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.FilterQueryProvider;
public class MediaAdapter extends BaseAdapter implements Filterable {
private Context mContext;
private OnClickListener mExpanderListener;
public class MediaAdapter extends CursorAdapter implements FilterQueryProvider {
public static final String[] ARTIST_FIELDS = { MediaStore.Audio.Artists.ARTIST };
public static final String[] ARTIST_FIELD_KEYS = { MediaStore.Audio.Artists.ARTIST_KEY };
public static final String[] ALBUM_FIELDS = { MediaStore.Audio.Albums.ARTIST, MediaStore.Audio.Albums.ALBUM };
// Why is there no artist_key column constant in the album MediaStore? The column does seem to exist.
public static final String[] ALBUM_FIELD_KEYS = { "artist_key", MediaStore.Audio.Albums.ALBUM_KEY };
public static final String[] SONG_FIELDS = { MediaStore.Audio.Media.ARTIST, MediaStore.Audio.Media.ALBUM, MediaStore.Audio.Media.TITLE };
public static final String[] SONG_FIELD_KEYS = { MediaStore.Audio.Media.ARTIST_KEY, MediaStore.Audio.Media.ALBUM_KEY, MediaStore.Audio.Media.TITLE_KEY };
private List<SongData> mObjects;
private SongData[] mAllObjects;
private ArrayFilter mFilter;
private long mLimiter;
private SongData mLimiterData;
private CharSequence mPublishedFilter;
private long mPublishedLimiter;
private Uri mStore;
private String[] mFields;
private String[] mFieldKeys;
private View.OnClickListener mExpanderListener;
private String mSelection;
private String[] mLimiter;
private CharSequence mConstraint;
private int mPrimaryField;
private int mSecondaryField;
public MediaAdapter(Context context, SongData[] allObjects, int primaryField, int secondaryField, View.OnClickListener expanderListener)
public MediaAdapter(Context context, Uri store, String[] fields, String[] fieldKeys, View.OnClickListener expanderListener, String selection)
{
mContext = context;
mAllObjects = allObjects;
mPrimaryField = primaryField;
mSecondaryField = secondaryField;
super(context, null, true);
mStore = store;
mFields = fields;
mFieldKeys = fieldKeys;
mExpanderListener = expanderListener;
mSelection = selection;
setFilterQueryProvider(this);
changeCursor(runQuery(null));
}
public void filter(CharSequence constraint, Filter.FilterListener listener)
{
mConstraint = constraint;
getFilter().filter(constraint, listener);
}
public Cursor runQuery(CharSequence constraint)
{
ContentResolver resolver = ContextApplication.getContext().getContentResolver();
StringBuilder selection = new StringBuilder();
String[] selectionArgs;
String limiter;
if (mSelection != null)
selection.append(mSelection);
if (mLimiter != null) {
int i = Math.min(mLimiter.length, mFields.length) - 1;
if (selection.length() != 0)
selection.append(" AND ");
selection.append(mFields[i]);
selection.append(" = ?");
limiter = mLimiter[i];
} else {
limiter = null;
}
if (constraint != null && constraint.length() != 0) {
String[] constraints = constraint.toString().split("\\s+");
int size = constraints.length;
if (limiter != null)
++size;
selectionArgs = new String[size];
int i = 0;
if (limiter != null) {
selectionArgs[0] = limiter;
i = 1;
}
String keys = mFieldKeys[0];
for (int j = 1; j != mFieldKeys.length; ++j)
keys += "||" + mFieldKeys[j];
for (int j = 0; j != constraints.length; ++i, ++j) {
selectionArgs[i] = '%' + MediaStore.Audio.keyFor(constraints[j]) + '%';
if (j != 0 || selection.length() != 0)
selection.append(" AND ");
selection.append(keys);
selection.append(" LIKE ?");
}
} else {
if (limiter != null)
selectionArgs = new String[] { limiter };
else
selectionArgs = null;
}
String[] projection;
if (mFields.length == 1)
projection = new String[] { BaseColumns._ID, mFields[0] };
else
projection = new String[] { BaseColumns._ID, mFields[mFields.length - 1], mFields[0] };
return resolver.query(mStore, projection, selection.toString(), selectionArgs, mFieldKeys[mFieldKeys.length - 1]);
}
public final boolean hasExpanders()
@ -69,231 +140,34 @@ public class MediaAdapter extends BaseAdapter implements Filterable {
return mExpanderListener != null;
}
@Override
public boolean hasStableIds()
{
return true;
}
public View getView(int position, View convertView, ViewGroup parent)
{
MediaView view = null;
try {
view = (MediaView)convertView;
} catch (ClassCastException e) {
}
if (view == null)
view = new MediaView(mContext);
view.updateMedia(get(position));
return view;
}
public Filter getFilter()
{
if (mFilter == null)
mFilter = new ArrayFilter();
return mFilter;
}
private static final String[] mRanges = { ".", "[2abc]", "[3def]", "[4ghi]", "[5jkl]", "[6mno]", "[7pqrs]", "[8tuv]", "[9wxyz]"};
private static Matcher createMatcher(String input)
{
String patternString = "";
for (int i = 0, end = input.length(); i != end; ++i) {
char c = input.charAt(i);
int value = c - '1';
if (value >= 0 && value < 9)
patternString += mRanges[value];
else
patternString += c;
}
return Pattern.compile(patternString, Pattern.CASE_INSENSITIVE).matcher("");
}
private class ArrayFilter extends Filter {
protected class ArrayFilterResults extends FilterResults {
public long limiter;
public ArrayFilterResults(List<SongData> list, long limiter)
{
values = list;
count = list.size();
this.limiter = limiter;
}
}
@Override
protected FilterResults performFiltering(CharSequence filter)
{
List<SongData> list;
if (filter != null && filter.length() == 0)
filter = null;
if ((filter == null && mPublishedFilter == null || mPublishedFilter != null && mPublishedFilter.equals(filter)) && mLimiter == mPublishedLimiter) {
list = mObjects;
} else if (filter == null && mLimiter == -1) {
list = Arrays.asList(mAllObjects);
} else {
Matcher[] matchers = null;
if (filter != null) {
String[] words = filter.toString().split("\\s+");
matchers = new Matcher[words.length];
for (int i = words.length; --i != -1; )
matchers[i] = createMatcher(words[i]);
}
int limiterField = limiterField(mLimiter);
long limiterId = limiterId(mLimiter);
int count = mAllObjects.length;
ArrayList<SongData> newValues = new ArrayList<SongData>();
newValues.ensureCapacity(count);
outer:
for (int i = 0; i != count; ++i) {
SongData song = mAllObjects[i];
if (mLimiter != -1 && song.getFieldId(limiterField) != limiterId)
continue;
if (filter != null) {
for (int j = matchers.length; --j != -1; ) {
if (matchers[j].reset(song.artist).find())
continue;
if (mPrimaryField > 1 && matchers[j].reset(song.album).find())
continue;
if (mPrimaryField > 2 && matchers[j].reset(song.title).find())
continue;
continue outer;
}
}
newValues.add(song);
}
newValues.trimToSize();
list = newValues;
}
return new ArrayFilterResults(list, mLimiter);
}
@SuppressWarnings("unchecked")
@Override
protected void publishResults(CharSequence filter, FilterResults results)
{
mObjects = (List<SongData>)results.values;
mPublishedFilter = filter == null || filter.length() == 0 ? null : filter;
mPublishedLimiter = ((ArrayFilterResults)results).limiter;
if (results.count == 0)
notifyDataSetInvalidated();
else
notifyDataSetChanged();
}
}
public void hideAll()
{
mObjects = new ArrayList<SongData>();
notifyDataSetInvalidated();
}
public void setLimiter(long limiter, SongData data)
public final void setLimiter(String[] limiter)
{
mLimiter = limiter;
mLimiterData = data;
getFilter().filter(mPublishedFilter);
getFilter().filter(mConstraint);
}
public final long getLimiter()
public final String[] getLimiter()
{
return mLimiter;
}
public final int getLimiterField()
public final int getLimiterLength()
{
if (mLimiter == -1)
return -1;
return limiterField(mLimiter);
}
public final SongData getLimiterData()
{
return mLimiterData;
}
private static final int ID_SHIFT = 2;
private static final int FIELD_MASK = ~(~0 << ID_SHIFT);
public static long makeLimiter(int field, SongData data)
{
return (data.getFieldId(field) << ID_SHIFT) + (field & FIELD_MASK);
}
public static int limiterField(long limiter)
{
return (int)(limiter & FIELD_MASK);
}
public static long limiterId(long limiter)
{
return limiter >> ID_SHIFT;
}
public int getCount()
{
if (mObjects == null) {
if (mAllObjects == null)
return 0;
return mAllObjects.length;
}
return mObjects.size();
}
public SongData get(int i)
{
if (mObjects == null) {
if (mAllObjects == null)
return null;
return mAllObjects[i];
}
if (i >= mObjects.size())
return null;
return mObjects.get(i);
}
public Object getItem(int i)
{
return get(i);
}
public long getItemId(int i)
{
SongData song = get(i);
if (song == null)
if (mLimiter == null)
return 0;
return song.getFieldId(mPrimaryField);
return mLimiter.length;
}
public Intent buildSongIntent(int action, int pos)
@Override
public void bindView(View view, Context context, Cursor cursor)
{
SongData song = get(pos);
if (song == null)
return null;
((MediaView)view).updateMedia(cursor);
}
Intent intent = new Intent(mContext, PlaybackService.class);
intent.putExtra("type", mPrimaryField);
intent.putExtra("action", action);
intent.putExtra("id", song.getFieldId(mPrimaryField));
intent.putExtra("title", song.getField(mPrimaryField));
return intent;
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent)
{
return new MediaView(context);
}
private static float mTextSize = -1;
@ -302,7 +176,9 @@ public class MediaAdapter extends BaseAdapter implements Filterable {
private int mViewHeight = -1;
public class MediaView extends View {
private SongData mData;
private long mId;
private String mTitle;
private String mSubTitle;
private boolean mExpanderPressed;
public MediaView(Context context)
@ -327,7 +203,7 @@ public class MediaAdapter extends BaseAdapter implements Filterable {
else
expanderHeight = 0;
if (mSecondaryField != -1)
if (mFields.length > 1)
textHeight = (int)(7 * mTextSize / 2);
else
textHeight = (int)(2 * mTextSize);
@ -344,7 +220,7 @@ public class MediaAdapter extends BaseAdapter implements Filterable {
@Override
public void onDraw(Canvas canvas)
{
if (mData == null)
if (mTitle == null)
return;
int width = getWidth();
@ -364,33 +240,32 @@ public class MediaAdapter extends BaseAdapter implements Filterable {
float allocatedHeight;
if (mSecondaryField != -1) {
if (mSubTitle != null) {
allocatedHeight = height / 2 - padding * 3 / 2;
paint.setColor(Color.GRAY);
canvas.drawText(mData.getField(mSecondaryField), padding, height / 2 + padding / 2 + (allocatedHeight - mTextSize) / 2 - paint.ascent(), paint);
canvas.drawText(mSubTitle, padding, height / 2 + padding / 2 + (allocatedHeight - mTextSize) / 2 - paint.ascent(), paint);
} else {
allocatedHeight = height - padding * 2;
}
paint.setColor(Color.WHITE);
canvas.drawText(mData.getField(mPrimaryField), padding, padding + (allocatedHeight - mTextSize) / 2 - paint.ascent(), paint);
canvas.drawText(mTitle, padding, padding + (allocatedHeight - mTextSize) / 2 - paint.ascent(), paint);
}
public final void updateMedia(SongData data)
public final int getFieldCount()
{
mData = data;
invalidate();
return mFields.length;
}
public final int getPrimaryField()
public final long getMediaId()
{
return mPrimaryField;
return mId;
}
public final SongData getExpanderData()
public final String getTitle()
{
return mData;
return mTitle;
}
public final boolean isExpanderPressed()
@ -398,6 +273,33 @@ public class MediaAdapter extends BaseAdapter implements Filterable {
return mExpanderPressed;
}
public final void updateMedia(Cursor cursor)
{
mId = cursor.getLong(0);
mTitle = cursor.getString(1);
if (mFields.length > 1)
mSubTitle = cursor.getString(2);
invalidate();
}
public final String[] getLimiter()
{
ContentResolver resolver = ContextApplication.getContext().getContentResolver();
String selection = mFields[mFields.length - 1] + " = ?";
String[] selectionArgs = { mTitle };
String[] projection = new String[mFields.length + 1];
projection[0] = BaseColumns._ID;
System.arraycopy(mFields, 0, projection, 1, mFields.length);
Cursor cursor = resolver.query(mStore, projection, selection, selectionArgs, null);
cursor.moveToNext();
String[] result = new String[cursor.getColumnCount() - 1];
for (int i = result.length; --i != -1; )
result[i] = cursor.getString(i + 1);
return result;
}
@Override
public boolean onTouchEvent(MotionEvent event)
{

View File

@ -622,14 +622,14 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On
loadPreference((String)message.obj);
break;
case DO_ITEM:
long id = message.obj == null ? -1 : ((Intent)message.obj).getLongExtra("id", -1);
Intent intent = (Intent)message.obj;
long id = message.obj == null ? -1 : intent.getLongExtra("id", -1);
if (id == -1) {
mQueuePos = 0;
} else {
Intent intent = (Intent)message.obj;
boolean enqueue = intent.getIntExtra("action", ACTION_PLAY) == ACTION_ENQUEUE;
long[] songs = Song.getAllSongIdsWith(intent.getIntExtra("type", SongData.FIELD_TITLE), id);
long[] songs = Song.getAllSongIdsWith(intent.getIntExtra("type", 3), id);
if (songs == null || songs.length == 0)
break;

View File

@ -131,13 +131,16 @@ public class Song implements Parcelable {
public static long[] getAllSongIdsWith(int type, long id)
{
if (type == SongData.FIELD_TITLE)
switch (type) {
case 3:
return new long[] { id };
else if (type == SongData.FIELD_ALBUM)
case 2:
return Song.getAllSongIds(MediaStore.Audio.Media.ALBUM_ID + '=' + id);
else if (type == SongData.FIELD_ARTIST)
case 1:
return Song.getAllSongIds(MediaStore.Audio.Media.ARTIST_ID + '=' + id);
return null;
default:
return null;
}
}
public void randomize()

View File

@ -1,163 +0,0 @@
/*
* Copyright (C) 2010 Christopher Eby <kreed@kreed.org>
*
* This file is part of Vanilla Music Player.
*
* Vanilla Music Player is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Vanilla Music Player 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.kreed.vanilla;
import java.util.Arrays;
import java.util.Comparator;
import android.content.ContentResolver;
import android.database.Cursor;
import android.net.Uri;
import android.provider.MediaStore;
import android.util.SparseArray;
public class SongData {
public static final int FIELD_ARTIST = 1;
public static final int FIELD_ALBUM = 2;
public static final int FIELD_TITLE = 3;
public long id;
public long albumId;
public long artistId;
public String title;
public String album;
public String artist;
private SongData(Cursor cursor)
{
id = cursor.getLong(0);
title = cursor.getString(1);
albumId = cursor.getLong(2);
album = cursor.getString(3);
artistId = cursor.getLong(4);
artist = cursor.getString(5);
}
public String getField(int field)
{
switch (field) {
case FIELD_TITLE:
return title;
case FIELD_ARTIST:
return artist;
case FIELD_ALBUM:
return album;
}
return null;
}
public long getFieldId(int field)
{
switch (field) {
case FIELD_TITLE:
return id;
case FIELD_ARTIST:
return artistId;
case FIELD_ALBUM:
return albumId;
}
return 0;
}
public static SongData[] getAllSongData()
{
Uri media = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
String[] projection = { MediaStore.Audio.Media._ID,
MediaStore.Audio.Media.TITLE,
MediaStore.Audio.Media.ALBUM_ID,
MediaStore.Audio.Media.ALBUM,
MediaStore.Audio.Media.ARTIST_ID,
MediaStore.Audio.Media.ARTIST };
String selection = MediaStore.Audio.Media.IS_MUSIC + "!=0";
ContentResolver resolver = ContextApplication.getContext().getContentResolver();
Cursor cursor = resolver.query(media, projection, selection, null, null);
if (cursor == null)
return null;
int count = cursor.getCount();
if (count == 0)
return null;
SongData[] songs = new SongData[count];
while (--count != -1) {
if (!cursor.moveToNext())
return null;
songs[count] = new SongData(cursor);
}
cursor.close();
return songs;
}
public static class TitleComparator implements Comparator<SongData> {
public int compare(SongData a, SongData b)
{
return a.title.compareToIgnoreCase(b.title);
}
}
public static class AlbumComparator implements IdComparator {
public int compare(SongData a, SongData b)
{
return a.album.compareToIgnoreCase(b.album);
}
public long getId(SongData song)
{
return song.albumId;
}
}
public static class ArtistComparator implements IdComparator {
public int compare(SongData a, SongData b)
{
return a.artist.compareToIgnoreCase(b.artist);
}
public long getId(SongData song)
{
return song.artistId;
}
}
public static interface IdComparator extends Comparator<SongData> {
public long getId(SongData song);
}
public static SongData[] filter(SongData[] songs, IdComparator comparator)
{
SparseArray<SongData> albums = new SparseArray<SongData>(songs.length);
for (int i = songs.length; --i != -1; ) {
SongData song = songs[i];
int id = (int)comparator.getId(song);
if (albums.get(id) == null)
albums.put(id, song);
}
SongData[] result = new SongData[albums.size()];
for (int i = result.length; --i != -1; )
result[i] = albums.valueAt(i);
Arrays.sort(result, comparator);
return result;
}
}

View File

@ -18,8 +18,6 @@
package org.kreed.vanilla;
import java.util.Arrays;
import org.kreed.vanilla.R;
import android.app.Dialog;
@ -29,9 +27,11 @@ import android.content.SharedPreferences;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.drawable.PaintDrawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.provider.MediaStore;
import android.text.Editable;
import android.text.InputType;
import android.text.TextUtils;
@ -71,12 +71,12 @@ public class SongSelector extends Dialog implements AdapterView.OnItemClickListe
return (MediaAdapter)getList(tab).getAdapter();
}
private void initializeList(int id, SongData[] songs, int lineA, int lineB, View.OnClickListener expanderListener)
private void initializeList(int id, Uri store, String[] fields, String[] fieldKeys, View.OnClickListener expanderListener, String selection)
{
ListView view = (ListView)findViewById(id);
view.setOnItemClickListener(this);
view.setOnCreateContextMenuListener(this);
view.setAdapter(new MediaAdapter(getContext(), songs, lineA, lineB, expanderListener));
view.setAdapter(new MediaAdapter(getContext(), store, fields, fieldKeys, expanderListener, selection));
}
public SongSelector(Context context)
@ -109,12 +109,9 @@ public class SongSelector extends Dialog implements AdapterView.OnItemClickListe
new Handler().post(new Runnable() {
public void run()
{
SongData[] songs = SongData.getAllSongData();
initializeList(R.id.artist_list, SongData.filter(songs, new SongData.ArtistComparator()), SongData.FIELD_ARTIST, -1, SongSelector.this);
initializeList(R.id.album_list, SongData.filter(songs, new SongData.AlbumComparator()), SongData.FIELD_ALBUM, SongData.FIELD_ARTIST, SongSelector.this);
Arrays.sort(songs, new SongData.TitleComparator());
initializeList(R.id.song_list, songs, SongData.FIELD_TITLE, SongData.FIELD_ARTIST, null);
initializeList(R.id.artist_list, MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI, MediaAdapter.ARTIST_FIELDS, MediaAdapter.ARTIST_FIELD_KEYS, SongSelector.this, null);
initializeList(R.id.album_list, MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI, MediaAdapter.ALBUM_FIELDS, MediaAdapter.ALBUM_FIELD_KEYS,SongSelector.this, null);
initializeList(R.id.song_list, MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, MediaAdapter.SONG_FIELDS, MediaAdapter.SONG_FIELD_KEYS, null, MediaStore.Audio.Media.IS_MUSIC + "!=0");
}
});
}
@ -145,36 +142,32 @@ public class SongSelector extends Dialog implements AdapterView.OnItemClickListe
return mTextFilter.onKeyDown(keyCode, event);
}
private void sendSongIntent(Intent intent)
private void sendSongIntent(MediaAdapter.MediaView view, int action)
{
int action = intent.getIntExtra("action", PlaybackService.ACTION_PLAY);
String title = intent.getStringExtra("title");
intent.removeExtra("title");
int res = action == PlaybackService.ACTION_PLAY ? R.string.playing : R.string.enqueued;
String text = getContext().getResources().getString(res, title);
String text = getContext().getResources().getString(res, view.getTitle());
Toast.makeText(getContext(), text, Toast.LENGTH_SHORT).show();
long id = view.getMediaId();
int field = view.getFieldCount();
Intent intent = new Intent(getContext(), PlaybackService.class);
intent.putExtra("type", field);
intent.putExtra("action", action);
intent.putExtra("id", id);
getContext().startService(intent);
mLastActedId = intent.getIntExtra("id", -1);
mLastActedId = id;
}
private void expand(MediaAdapter.MediaView view)
{
int field = view.getPrimaryField();
SongData data = view.getExpanderData();
long limiter = MediaAdapter.makeLimiter(field, data);
String[] limiter = view.getLimiter();
for (int i = field; i != 3; ++i) {
MediaAdapter adapter = getAdapter(i);
if (adapter.getLimiter() != limiter) {
adapter.hideAll();
adapter.setLimiter(limiter, data);
}
}
for (int i = limiter.length; i != 3; ++i)
getAdapter(i).setLimiter(limiter);
mTabHost.setCurrentTab(field);
mTabHost.setCurrentTab(limiter.length);
}
public void onItemClick(AdapterView<?> list, View view, int pos, long id)
@ -185,7 +178,7 @@ public class SongSelector extends Dialog implements AdapterView.OnItemClickListe
else if (id == mLastActedId)
dismiss();
else
sendSongIntent(((MediaAdapter)list.getAdapter()).buildSongIntent(mDefaultAction, pos));
sendSongIntent(mediaView, mDefaultAction);
}
public void afterTextChanged(Editable editable)
@ -200,7 +193,7 @@ public class SongSelector extends Dialog implements AdapterView.OnItemClickListe
{
MediaAdapter adapter = getAdapter(mTabHost.getCurrentTab());
if (adapter != null)
adapter.getFilter().filter(text, this);
adapter.filter(text, this);
}
private void updateLimiterViews()
@ -214,21 +207,20 @@ public class SongSelector extends Dialog implements AdapterView.OnItemClickListe
if (adapter == null)
return;
int field = adapter.getLimiterField();
SongData data = adapter.getLimiterData();
if (field == -1)
String[] limiter = adapter.getLimiter();
if (limiter == null)
return;
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
params.leftMargin = 5;
for (int i = SongData.FIELD_ARTIST; i <= field; ++i) {
for (int i = 0; i != limiter.length; ++i) {
PaintDrawable background = new PaintDrawable(Color.GRAY);
background.setCornerRadius(5);
TextView view = new TextView(getContext());
view.setSingleLine();
view.setEllipsize(TextUtils.TruncateAt.MARQUEE);
view.setText(data.getField(i) + " | X");
view.setText(limiter[i] + " | X");
view.setTextColor(Color.WHITE);
view.setBackgroundDrawable(background);
view.setLayoutParams(params);
@ -249,14 +241,20 @@ public class SongSelector extends Dialog implements AdapterView.OnItemClickListe
if (view == mClearButton) {
mTextFilter.setText("");
} else {
int field = (Integer)view.getTag() - 1;
SongData data = getAdapter(mTabHost.getCurrentTab()).getLimiterData();
long limiter = field == 0 ? -1 : MediaAdapter.makeLimiter(field, data);
int i = (Integer)view.getTag();
String[] limiter;
if (i == 0) {
limiter = null;
} else {
String[] oldLimiter = getAdapter(mTabHost.getCurrentTab()).getLimiter();
limiter = new String[i];
System.arraycopy(oldLimiter, 0, limiter, 0, i);
}
for (int i = 3; --i != -1; ) {
MediaAdapter adapter = getAdapter(i);
if (adapter.getLimiterField() > field)
adapter.setLimiter(limiter, data);
for (int j = 3; --j != -1; ) {
MediaAdapter adapter = getAdapter(j);
if (adapter.getLimiterLength() > i)
adapter.setLimiter(limiter);
}
updateLimiterViews();
@ -268,29 +266,30 @@ public class SongSelector extends Dialog implements AdapterView.OnItemClickListe
private static final int MENU_EXPAND = 2;
@Override
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo info)
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo absInfo)
{
MediaAdapter adapter = (MediaAdapter)((ListView)view).getAdapter();
int pos = (int)((AdapterView.AdapterContextMenuInfo)info).position;
menu.add(0, MENU_PLAY, 0, R.string.play).setIntent(adapter.buildSongIntent(PlaybackService.ACTION_PLAY, pos));
menu.add(0, MENU_ENQUEUE, 0, R.string.enqueue).setIntent(adapter.buildSongIntent(PlaybackService.ACTION_ENQUEUE, pos));
if (adapter.hasExpanders())
menu.add(0, MENU_PLAY, 0, R.string.play);
menu.add(0, MENU_ENQUEUE, 0, R.string.enqueue);
if (((MediaAdapter)((ListView)view).getAdapter()).hasExpanders())
menu.add(0, MENU_EXPAND, 0, R.string.expand);
}
@Override
public boolean onContextItemSelected(MenuItem item)
{
MediaAdapter.MediaView view = (MediaAdapter.MediaView)((AdapterView.AdapterContextMenuInfo)item.getMenuInfo()).targetView;
int action = PlaybackService.ACTION_PLAY;
switch (item.getItemId()) {
case MENU_EXPAND:
expand((MediaAdapter.MediaView)((AdapterView.AdapterContextMenuInfo)item.getMenuInfo()).targetView);
expand(view);
break;
case MENU_PLAY:
case MENU_ENQUEUE:
Intent intent = item.getIntent();
action = PlaybackService.ACTION_ENQUEUE;
// fall through
case MENU_PLAY:
if (mDefaultIsLastAction)
mDefaultAction = intent.getIntExtra("action", PlaybackService.ACTION_PLAY);
sendSongIntent(intent);
mDefaultAction = action;
sendSongIntent(view, action);
break;
default:
return false;
@ -311,7 +310,7 @@ public class SongSelector extends Dialog implements AdapterView.OnItemClickListe
{
CharSequence text = mTextFilter.getText();
for (int i = 3; --i != -1; )
getAdapter(i).getFilter().filter(text);
getAdapter(i).filter(text, null);
}
@Override