Split library ListView/adapter related code out into LibraryPagerAdapter
This commit is contained in:
parent
78acb5f627
commit
20517a8281
@ -191,7 +191,10 @@ public class FileSystemAdapter extends BaseAdapter implements LibraryAdapter {
|
||||
@Override
|
||||
public void setFilter(String filter)
|
||||
{
|
||||
mFilter = SPACE_SPLIT.split(filter.toLowerCase());
|
||||
if (filter == null)
|
||||
mFilter = null;
|
||||
else
|
||||
mFilter = SPACE_SPLIT.split(filter.toLowerCase());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -247,7 +250,7 @@ public class FileSystemAdapter extends BaseAdapter implements LibraryAdapter {
|
||||
@Override
|
||||
public void onEvent(int event, String path)
|
||||
{
|
||||
mActivity.postRequestRequery(FileSystemAdapter.this);
|
||||
mActivity.mPagerAdapter.postRequestRequery(FileSystemAdapter.this);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2010, 2011 Christopher Eby <kreed@kreed.org>
|
||||
* Copyright (C) 2012 Christopher Eby <kreed@kreed.org>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@ -28,7 +28,6 @@ import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.Resources;
|
||||
import android.database.ContentObserver;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Color;
|
||||
@ -36,10 +35,8 @@ import android.graphics.drawable.PaintDrawable;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.provider.MediaStore;
|
||||
import android.support.v4.view.PagerAdapter;
|
||||
import android.support.v4.view.ViewPager;
|
||||
import android.text.Editable;
|
||||
import android.text.TextUtils;
|
||||
@ -77,23 +74,50 @@ public class LibraryActivity
|
||||
, TextWatcher
|
||||
, DialogInterface.OnClickListener
|
||||
, DialogInterface.OnDismissListener
|
||||
, ViewPager.OnPageChangeListener
|
||||
{
|
||||
/**
|
||||
* Action for row click: play the row.
|
||||
*/
|
||||
public static final int ACTION_PLAY = 0;
|
||||
/**
|
||||
* Action for row click: enqueue the row.
|
||||
*/
|
||||
public static final int ACTION_ENQUEUE = 1;
|
||||
/**
|
||||
* Action for row click: perform the last used action.
|
||||
*/
|
||||
public static final int ACTION_LAST_USED = 2;
|
||||
/**
|
||||
* Action for row click: play all the songs in the adapter, starting with
|
||||
* the current row.
|
||||
*/
|
||||
public static final int ACTION_PLAY_ALL = 3;
|
||||
/**
|
||||
* Action for row click: enqueue all the songs in the adapter, starting with
|
||||
* the current row.
|
||||
*/
|
||||
public static final int ACTION_ENQUEUE_ALL = 4;
|
||||
/**
|
||||
* Action for row click: do nothing.
|
||||
*/
|
||||
public static final int ACTION_DO_NOTHING = 5;
|
||||
/**
|
||||
* Action for row click: expand the row.
|
||||
*/
|
||||
public static final int ACTION_EXPAND = 6;
|
||||
/**
|
||||
* The SongTimeline add song modes corresponding to each relevant action.
|
||||
*/
|
||||
private static final int[] modeForAction =
|
||||
{ SongTimeline.MODE_PLAY, SongTimeline.MODE_ENQUEUE, -1,
|
||||
SongTimeline.MODE_PLAY_ID_FIRST, SongTimeline.MODE_ENQUEUE_ID_FIRST };
|
||||
|
||||
public ViewPager mViewPager;
|
||||
|
||||
private View mSearchBox;
|
||||
private boolean mSearchBoxVisible;
|
||||
TextView mTextFilter;
|
||||
|
||||
private TextView mTextFilter;
|
||||
private View mClearButton;
|
||||
|
||||
private View mActionControls;
|
||||
@ -106,151 +130,27 @@ public class LibraryActivity
|
||||
private HorizontalScrollView mLimiterScroller;
|
||||
private ViewGroup mLimiterViews;
|
||||
|
||||
/**
|
||||
* The action to execute when a row is tapped.
|
||||
*/
|
||||
private int mDefaultAction;
|
||||
|
||||
/**
|
||||
* The last used action from the menu. Used with ACTION_LAST_USED.
|
||||
*/
|
||||
private int mLastAction = ACTION_PLAY;
|
||||
/**
|
||||
* The id of the media that was last pressed in the current adapter. Used to
|
||||
* open the playback activity when an item is pressed twice.
|
||||
*/
|
||||
private long mLastActedId;
|
||||
|
||||
/**
|
||||
* The number of adapters/lists (determines array sizes).
|
||||
* The pager adapter that manages each media ListView.
|
||||
*/
|
||||
private static final int ADAPTER_COUNT = 6;
|
||||
public LibraryPagerAdapter mPagerAdapter;
|
||||
/**
|
||||
* The ListView for each adapter, in the same order as MediaUtils.TYPE_*.
|
||||
* The adapter for the currently visible list.
|
||||
*/
|
||||
final ListView[] mLists = new ListView[ADAPTER_COUNT];
|
||||
/**
|
||||
* Whether the adapter corresponding to each index has stale data.
|
||||
*/
|
||||
final boolean[] mRequeryNeeded = new boolean[ADAPTER_COUNT];
|
||||
/**
|
||||
* Each adapter, in the same order as MediaUtils.TYPE_*.
|
||||
*/
|
||||
final LibraryAdapter[] mAdapters = new LibraryAdapter[ADAPTER_COUNT];
|
||||
/**
|
||||
* The human-readable title for each page.
|
||||
*/
|
||||
public static final int[] TITLES = { R.string.artists, R.string.albums, R.string.songs,
|
||||
R.string.playlists, R.string.genres, R.string.files };
|
||||
/**
|
||||
* Limiters that should be passed to an adapter constructor.
|
||||
*/
|
||||
public final Limiter[] mPendingLimiters = new Limiter[ADAPTER_COUNT];
|
||||
MediaAdapter mArtistAdapter;
|
||||
MediaAdapter mAlbumAdapter;
|
||||
MediaAdapter mSongAdapter;
|
||||
MediaAdapter mPlaylistAdapter;
|
||||
MediaAdapter mGenreAdapter;
|
||||
FileSystemAdapter mFilesAdapter;
|
||||
LibraryAdapter mCurrentAdapter;
|
||||
|
||||
private final ContentObserver mPlaylistObserver = new ContentObserver(null) {
|
||||
@Override
|
||||
public void onChange(boolean selfChange)
|
||||
{
|
||||
if (mPlaylistAdapter != null) {
|
||||
postRequestRequery(mPlaylistAdapter);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private final PagerAdapter mPagerAdapter = new PagerAdapter() {
|
||||
@Override
|
||||
public Object instantiateItem(ViewGroup container, int position)
|
||||
{
|
||||
ListView view = mLists[position];
|
||||
|
||||
if (view == null) {
|
||||
LibraryAdapter adapter;
|
||||
|
||||
switch (position) {
|
||||
case 0:
|
||||
adapter = mArtistAdapter = new MediaAdapter(LibraryActivity.this, MediaUtils.TYPE_ARTIST, true, true, null);
|
||||
mArtistAdapter.setHeaderText(getHeaderText());
|
||||
break;
|
||||
case 1:
|
||||
adapter = mAlbumAdapter = new MediaAdapter(LibraryActivity.this, MediaUtils.TYPE_ALBUM, true, true, mPendingLimiters[position]);
|
||||
mAlbumAdapter.setHeaderText(getHeaderText());
|
||||
break;
|
||||
case 2:
|
||||
adapter = mSongAdapter = new MediaAdapter(LibraryActivity.this, MediaUtils.TYPE_SONG, false, true, mPendingLimiters[position]);
|
||||
mSongAdapter.setHeaderText(getHeaderText());
|
||||
break;
|
||||
case 3:
|
||||
adapter = mPlaylistAdapter = new MediaAdapter(LibraryActivity.this, MediaUtils.TYPE_PLAYLIST, true, false, null);
|
||||
break;
|
||||
case 4:
|
||||
adapter = mGenreAdapter = new MediaAdapter(LibraryActivity.this, MediaUtils.TYPE_GENRE, true, false, null);
|
||||
break;
|
||||
case 5:
|
||||
adapter = mFilesAdapter = new FileSystemAdapter(LibraryActivity.this, mPendingLimiters[position]);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid position: " + position);
|
||||
}
|
||||
|
||||
view = new ListView(LibraryActivity.this);
|
||||
view.setOnItemClickListener(LibraryActivity.this);
|
||||
view.setOnCreateContextMenuListener(LibraryActivity.this);
|
||||
view.setDivider(null);
|
||||
view.setFastScrollEnabled(true);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
|
||||
CompatHoneycomb.setFastScrollAlwaysVisible(view, true);
|
||||
}
|
||||
view.setScrollBarStyle(View.SCROLLBARS_OUTSIDE_INSET);
|
||||
|
||||
view.setAdapter(adapter);
|
||||
if (position != 5)
|
||||
loadSortOrder((MediaAdapter)adapter);
|
||||
|
||||
String filter = mTextFilter.getText().toString();
|
||||
if (filter.length() != 0) {
|
||||
adapter.setFilter(filter);
|
||||
}
|
||||
|
||||
mAdapters[position] = adapter;
|
||||
mLists[position] = view;
|
||||
mRequeryNeeded[position] = true;
|
||||
|
||||
if (mCurrentAdapter == null && mViewPager.getCurrentItem() == position) {
|
||||
// Special case: for first time initialization onPageSelected
|
||||
// is not called (for initial position = 0) or called before
|
||||
// the adapter is initialized (for all other initial positions).
|
||||
// So do required work here.
|
||||
mCurrentAdapter = adapter;
|
||||
updateLimiterViews();
|
||||
}
|
||||
}
|
||||
|
||||
requeryIfNeeded(position);
|
||||
container.addView(view);
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyItem(ViewGroup container, int position, Object object)
|
||||
{
|
||||
container.removeView(mLists[position]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getPageTitle(int position)
|
||||
{
|
||||
return getResources().getText(TITLES[position]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount()
|
||||
{
|
||||
return ADAPTER_COUNT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isViewFromObject(View view, Object object)
|
||||
{
|
||||
return view == object;
|
||||
}
|
||||
};
|
||||
private LibraryAdapter mCurrentAdapter;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle state)
|
||||
@ -275,12 +175,16 @@ public class LibraryActivity
|
||||
mLimiterScroller = (HorizontalScrollView)findViewById(R.id.limiter_scroller);
|
||||
mLimiterViews = (ViewGroup)findViewById(R.id.limiter_layout);
|
||||
|
||||
mViewPager = (ViewPager)findViewById(R.id.pager);
|
||||
mViewPager.setAdapter(mPagerAdapter);
|
||||
LibraryPagerAdapter pagerAdapter = new LibraryPagerAdapter(this, mLooper);
|
||||
mPagerAdapter = pagerAdapter;
|
||||
|
||||
ViewPager pager = (ViewPager)findViewById(R.id.pager);
|
||||
pager.setAdapter(pagerAdapter);
|
||||
mViewPager = pager;
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
|
||||
CompatHoneycomb.addActionBarTabs(this);
|
||||
mViewPager.setOnPageChangeListener(this);
|
||||
pager.setOnPageChangeListener(pagerAdapter);
|
||||
|
||||
View controls = getLayoutInflater().inflate(R.layout.actionbar_controls, null);
|
||||
mTitle = (TextView)controls.findViewById(R.id.title);
|
||||
@ -290,8 +194,8 @@ public class LibraryActivity
|
||||
mActionControls = controls;
|
||||
} else {
|
||||
TabPageIndicator tabs = new TabPageIndicator(this);
|
||||
tabs.setViewPager(mViewPager);
|
||||
tabs.setOnPageChangeListener(this);
|
||||
tabs.setViewPager(pager);
|
||||
tabs.setOnPageChangeListener(pagerAdapter);
|
||||
|
||||
LinearLayout content = (LinearLayout)findViewById(R.id.content);
|
||||
content.addView(tabs, 0, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
|
||||
@ -326,8 +230,6 @@ public class LibraryActivity
|
||||
}
|
||||
}
|
||||
|
||||
getContentResolver().registerContentObserver(MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI, true, mPlaylistObserver);
|
||||
|
||||
loadAlbumIntent(getIntent());
|
||||
}
|
||||
|
||||
@ -370,7 +272,12 @@ public class LibraryActivity
|
||||
String[] fields = { intent.getStringExtra("artist"), intent.getStringExtra("album") };
|
||||
String data = String.format("album_id=%d", albumId);
|
||||
Limiter limiter = new Limiter(MediaUtils.TYPE_ALBUM, fields, data);
|
||||
setLimiter(limiter, true);
|
||||
int tab = mPagerAdapter.setLimiter(limiter);
|
||||
if (tab == mViewPager.getCurrentItem())
|
||||
updateLimiterViews();
|
||||
else
|
||||
mViewPager.setCurrentItem(tab);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -387,26 +294,16 @@ public class LibraryActivity
|
||||
@Override
|
||||
public void onRestoreInstanceState(Bundle in)
|
||||
{
|
||||
super.onRestoreInstanceState(in);
|
||||
if (in.getBoolean("search_box_visible"))
|
||||
setSearchBoxVisible(true);
|
||||
mPendingLimiters[1] = (Limiter)in.getSerializable("limiter_albums");
|
||||
mPendingLimiters[2] = (Limiter)in.getSerializable("limiter_songs");
|
||||
mPendingLimiters[5] = (Limiter)in.getSerializable("limiter_files");
|
||||
super.onRestoreInstanceState(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle out)
|
||||
{
|
||||
super.onSaveInstanceState(out);
|
||||
|
||||
out.putBoolean("search_box_visible", mSearchBoxVisible);
|
||||
if (mAlbumAdapter != null)
|
||||
out.putSerializable("limiter_albums", mAlbumAdapter.getLimiter());
|
||||
if (mSongAdapter != null)
|
||||
out.putSerializable("limiter_songs", mSongAdapter.getLimiter());
|
||||
if (mFilesAdapter != null)
|
||||
out.putSerializable("limiter_files", mFilesAdapter.getLimiter());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -448,31 +345,18 @@ public class LibraryActivity
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns either "Play All" or "Enqueue All", depending on the current
|
||||
* default action.
|
||||
*/
|
||||
public String getHeaderText()
|
||||
{
|
||||
int action = mDefaultAction;
|
||||
if (action == ACTION_LAST_USED)
|
||||
action = mLastAction;
|
||||
return getString(action == ACTION_ENQUEUE || action == ACTION_ENQUEUE_ALL ? R.string.enqueue_all : R.string.play_all);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the first row of the lists with the appropriate action (play all
|
||||
* or enqueue all).
|
||||
*/
|
||||
private void updateHeaders()
|
||||
{
|
||||
String text = getHeaderText();
|
||||
if (mArtistAdapter != null)
|
||||
mArtistAdapter.setHeaderText(text);
|
||||
if (mAlbumAdapter != null)
|
||||
mAlbumAdapter.setHeaderText(text);
|
||||
if (mSongAdapter != null)
|
||||
mSongAdapter.setHeaderText(text);
|
||||
int action = mDefaultAction;
|
||||
if (action == ACTION_LAST_USED)
|
||||
action = mLastAction;
|
||||
boolean isEnqueue = action == ACTION_ENQUEUE || action == ACTION_ENQUEUE_ALL;
|
||||
String text = getString(isEnqueue ? R.string.enqueue_all : R.string.play_all);
|
||||
mPagerAdapter.setHeaderText(text);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -484,17 +368,13 @@ public class LibraryActivity
|
||||
*/
|
||||
private void pickSongs(Intent intent, int action)
|
||||
{
|
||||
if (action == ACTION_LAST_USED)
|
||||
action = mLastAction;
|
||||
|
||||
long id = intent.getLongExtra("id", -1);
|
||||
|
||||
boolean all = false;
|
||||
int mode = action;
|
||||
if (action == ACTION_PLAY_ALL || action == ACTION_ENQUEUE_ALL) {
|
||||
LibraryAdapter adapter = mCurrentAdapter;
|
||||
boolean notPlayAllAdapter = adapter != mSongAdapter && adapter != mAlbumAdapter
|
||||
&& adapter != mArtistAdapter || id == MediaView.HEADER_ID;
|
||||
int type = mCurrentAdapter.getMediaType();
|
||||
boolean notPlayAllAdapter = type > MediaUtils.TYPE_SONG || id == MediaView.HEADER_ID;
|
||||
if (mode == ACTION_ENQUEUE_ALL && notPlayAllAdapter) {
|
||||
mode = ACTION_ENQUEUE;
|
||||
} else if (mode == ACTION_PLAY_ALL && notPlayAllAdapter) {
|
||||
@ -527,115 +407,11 @@ public class LibraryActivity
|
||||
{
|
||||
int type = intent.getIntExtra("type", 1);
|
||||
long id = intent.getLongExtra("id", -1);
|
||||
setLimiter(mAdapters[type - 1].buildLimiter(id), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear a limiter.
|
||||
*
|
||||
* @param type Which type of limiter to clear.
|
||||
*/
|
||||
private void clearLimiter(int type)
|
||||
{
|
||||
if (type == MediaUtils.TYPE_FILE) {
|
||||
if (mFilesAdapter == null) {
|
||||
mPendingLimiters[5] = null;
|
||||
} else {
|
||||
mFilesAdapter.setLimiter(null);
|
||||
requestRequery(mFilesAdapter);
|
||||
}
|
||||
} else {
|
||||
if (mAlbumAdapter == null) {
|
||||
mPendingLimiters[1] = null;
|
||||
} else {
|
||||
mAlbumAdapter.setLimiter(null);
|
||||
loadSortOrder(mAlbumAdapter);
|
||||
requestRequery(mAlbumAdapter);
|
||||
}
|
||||
if (mSongAdapter == null) {
|
||||
mPendingLimiters[2] = null;
|
||||
} else {
|
||||
mSongAdapter.setLimiter(null);
|
||||
loadSortOrder(mSongAdapter);
|
||||
requestRequery(mSongAdapter);
|
||||
}
|
||||
}
|
||||
updateLimiterViews();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the adapters with the given limiter.
|
||||
*
|
||||
* @param switchTab If true, will switch to the tab appropriate for
|
||||
* expanding a row.
|
||||
*/
|
||||
private void setLimiter(Limiter limiter, boolean switchTab)
|
||||
{
|
||||
int tab;
|
||||
|
||||
switch (limiter.type) {
|
||||
case MediaUtils.TYPE_ALBUM:
|
||||
if (mSongAdapter == null) {
|
||||
mPendingLimiters[2] = limiter;
|
||||
} else {
|
||||
mSongAdapter.setLimiter(limiter);
|
||||
loadSortOrder(mSongAdapter);
|
||||
requestRequery(mSongAdapter);
|
||||
}
|
||||
tab = 2;
|
||||
break;
|
||||
case MediaUtils.TYPE_ARTIST:
|
||||
if (mAlbumAdapter == null) {
|
||||
mPendingLimiters[1] = limiter;
|
||||
} else {
|
||||
mAlbumAdapter.setLimiter(limiter);
|
||||
loadSortOrder(mAlbumAdapter);
|
||||
requestRequery(mAlbumAdapter);
|
||||
}
|
||||
if (mSongAdapter == null) {
|
||||
mPendingLimiters[2] = limiter;
|
||||
} else {
|
||||
mSongAdapter.setLimiter(limiter);
|
||||
loadSortOrder(mSongAdapter);
|
||||
requestRequery(mSongAdapter);
|
||||
}
|
||||
tab = 1;
|
||||
break;
|
||||
case MediaUtils.TYPE_GENRE:
|
||||
if (mAlbumAdapter == null) {
|
||||
mPendingLimiters[1] = limiter;
|
||||
} else {
|
||||
mAlbumAdapter.setLimiter(limiter);
|
||||
loadSortOrder(mAlbumAdapter);
|
||||
requestRequery(mAlbumAdapter);
|
||||
}
|
||||
if (mSongAdapter == null) {
|
||||
mPendingLimiters[2] = null;
|
||||
} else {
|
||||
mSongAdapter.setLimiter(limiter);
|
||||
loadSortOrder(mSongAdapter);
|
||||
requestRequery(mSongAdapter);
|
||||
}
|
||||
tab = 2;
|
||||
break;
|
||||
case MediaUtils.TYPE_FILE:
|
||||
if (mFilesAdapter == null) {
|
||||
mPendingLimiters[5] = limiter;
|
||||
} else {
|
||||
mFilesAdapter.setLimiter(limiter);
|
||||
requestRequery(mFilesAdapter);
|
||||
}
|
||||
tab = 5;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported limiter type: " + limiter.type);
|
||||
}
|
||||
|
||||
if (switchTab && mViewPager.getCurrentItem() != tab) {
|
||||
mViewPager.setCurrentItem(tab);
|
||||
} else {
|
||||
int tab = mPagerAdapter.setLimiter(mPagerAdapter.mAdapters[type - 1].buildLimiter(id));
|
||||
if (tab == mViewPager.getCurrentItem())
|
||||
updateLimiterViews();
|
||||
}
|
||||
else
|
||||
mViewPager.setCurrentItem(tab);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -653,8 +429,10 @@ public class LibraryActivity
|
||||
MediaView mediaView = (MediaView)view;
|
||||
LibraryAdapter adapter = (LibraryAdapter)list.getAdapter();
|
||||
int action = mDefaultAction;
|
||||
if (action == ACTION_LAST_USED)
|
||||
action = mLastAction;
|
||||
if (mediaView.isRightBitmapPressed() || action == ACTION_EXPAND && mediaView.hasRightBitmap()) {
|
||||
if (adapter == mPlaylistAdapter)
|
||||
if (adapter.getMediaType() == MediaUtils.TYPE_PLAYLIST)
|
||||
editPlaylist(mediaView.getMediaId(), mediaView.getTitle());
|
||||
else
|
||||
expand(createClickIntent(adapter, mediaView));
|
||||
@ -683,13 +461,7 @@ public class LibraryActivity
|
||||
@Override
|
||||
public void onTextChanged(CharSequence text, int start, int before, int count)
|
||||
{
|
||||
String filter = text.toString();
|
||||
for (LibraryAdapter adapter : mAdapters) {
|
||||
if (adapter != null) {
|
||||
adapter.setFilter(filter);
|
||||
requestRequery(adapter);
|
||||
}
|
||||
}
|
||||
mPagerAdapter.setFilter(text.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -699,9 +471,8 @@ public class LibraryActivity
|
||||
{
|
||||
mLimiterViews.removeAllViews();
|
||||
|
||||
LibraryAdapter adapter = mCurrentAdapter;
|
||||
Limiter limiterData;
|
||||
if (adapter != null && (limiterData = adapter.getLimiter()) != null) {
|
||||
Limiter limiterData = mPagerAdapter.getCurrentLimiter();
|
||||
if (limiterData != null) {
|
||||
String[] limiter = limiterData.names;
|
||||
|
||||
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
|
||||
@ -745,7 +516,7 @@ public class LibraryActivity
|
||||
// a limiter view was clicked
|
||||
int i = (Integer)view.getTag();
|
||||
|
||||
Limiter limiter = mCurrentAdapter.getLimiter();
|
||||
Limiter limiter = mPagerAdapter.getCurrentLimiter();
|
||||
int type = limiter.type;
|
||||
if (i == 1 && type == MediaUtils.TYPE_ALBUM) {
|
||||
ContentResolver resolver = getContentResolver();
|
||||
@ -756,7 +527,8 @@ public class LibraryActivity
|
||||
if (cursor.moveToNext()) {
|
||||
String[] fields = { limiter.names[0] };
|
||||
String data = String.format("artist_id=%d", cursor.getLong(0));
|
||||
setLimiter(new Limiter(MediaUtils.TYPE_ARTIST, fields, data), false);
|
||||
mPagerAdapter.setLimiter(new Limiter(MediaUtils.TYPE_ARTIST, fields, data));
|
||||
updateLimiterViews();
|
||||
}
|
||||
cursor.close();
|
||||
}
|
||||
@ -767,9 +539,11 @@ public class LibraryActivity
|
||||
while (--diff != -1) {
|
||||
file = file.getParentFile();
|
||||
}
|
||||
setLimiter(FileSystemAdapter.buildLimiter(file), false);
|
||||
mPagerAdapter.setLimiter(FileSystemAdapter.buildLimiter(file));
|
||||
updateLimiterViews();
|
||||
} else {
|
||||
clearLimiter(type);
|
||||
mPagerAdapter.clearLimiter(type);
|
||||
updateLimiterViews();
|
||||
}
|
||||
} else {
|
||||
super.onClick(view);
|
||||
@ -828,7 +602,7 @@ public class LibraryActivity
|
||||
if (type == MediaUtils.TYPE_FILE) {
|
||||
query = MediaUtils.buildFileQuery(intent.getStringExtra("file"), projection);
|
||||
} else if (all || id == MediaView.HEADER_ID) {
|
||||
query = ((MediaAdapter)mAdapters[type - 1]).buildSongQuery(projection);
|
||||
query = ((MediaAdapter)mPagerAdapter.mAdapters[type - 1]).buildSongQuery(projection);
|
||||
query.setExtra(id);
|
||||
} else {
|
||||
query = MediaUtils.buildQuery(type, id, projection, null);
|
||||
@ -865,7 +639,8 @@ public class LibraryActivity
|
||||
Intent intent = createClickIntent(adapter, view);
|
||||
|
||||
boolean isHeader = view.getMediaId() == MediaView.HEADER_ID;
|
||||
boolean isAllAdapter = adapter == mArtistAdapter || adapter == mAlbumAdapter || adapter == mSongAdapter;
|
||||
int type = adapter.getMediaType();
|
||||
boolean isAllAdapter = type <= MediaUtils.TYPE_SONG;
|
||||
|
||||
if (isHeader)
|
||||
menu.setHeaderTitle(getString(R.string.all_songs));
|
||||
@ -878,7 +653,7 @@ public class LibraryActivity
|
||||
menu.add(0, MENU_ENQUEUE, 0, R.string.enqueue).setIntent(intent);
|
||||
if (isAllAdapter)
|
||||
menu.add(0, MENU_ENQUEUE_ALL, 0, R.string.enqueue_all).setIntent(intent);
|
||||
if (adapter == mPlaylistAdapter) {
|
||||
if (type == MediaUtils.TYPE_PLAYLIST) {
|
||||
menu.add(0, MENU_RENAME_PLAYLIST, 0, R.string.rename).setIntent(intent);
|
||||
menu.add(0, MENU_EDIT, 0, R.string.edit).setIntent(intent);
|
||||
}
|
||||
@ -962,6 +737,10 @@ public class LibraryActivity
|
||||
switch (item.getItemId()) {
|
||||
case MENU_EXPAND:
|
||||
expand(intent);
|
||||
if (mDefaultAction == ACTION_LAST_USED && mLastAction != ACTION_EXPAND) {
|
||||
mLastAction = ACTION_EXPAND;
|
||||
updateHeaders();
|
||||
}
|
||||
break;
|
||||
case MENU_ENQUEUE:
|
||||
pickSongs(intent, ACTION_ENQUEUE);
|
||||
@ -1039,7 +818,8 @@ public class LibraryActivity
|
||||
@Override
|
||||
public boolean onPrepareOptionsMenu(Menu menu)
|
||||
{
|
||||
menu.findItem(MENU_SORT).setEnabled(mCurrentAdapter != mFilesAdapter);
|
||||
LibraryAdapter adapter = mCurrentAdapter;
|
||||
menu.findItem(MENU_SORT).setEnabled(adapter != null && adapter.getMediaType() != MediaUtils.TYPE_FILE);
|
||||
return super.onPrepareOptionsMenu(menu);
|
||||
}
|
||||
|
||||
@ -1104,24 +884,10 @@ public class LibraryActivity
|
||||
* obj.
|
||||
*/
|
||||
private static final int MSG_RENAME_PLAYLIST = 13;
|
||||
/**
|
||||
* Called by MediaAdapters to requery their data on the worker thread.
|
||||
* obj will contain the MediaAdapter.
|
||||
*/
|
||||
private static final int MSG_RUN_QUERY = 14;
|
||||
/**
|
||||
* Call addToPlaylist with data from the intent in obj.
|
||||
*/
|
||||
private static final int MSG_ADD_TO_PLAYLIST = 15;
|
||||
/**
|
||||
* Save the sort mode for the adapter passed in obj.
|
||||
*/
|
||||
private static final int MSG_SAVE_SORT = 16;
|
||||
/**
|
||||
* Call {@link LibraryActivity#requestRequery(LibraryAdapter)} on the adapter
|
||||
* passed in obj.
|
||||
*/
|
||||
private static final int MSG_REQUEST_REQUERY = 17;
|
||||
|
||||
@Override
|
||||
public boolean handleMessage(Message message)
|
||||
@ -1154,31 +920,6 @@ public class LibraryActivity
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MSG_RUN_QUERY: {
|
||||
final LibraryAdapter adapter = (LibraryAdapter)message.obj;
|
||||
final Object data = adapter.query();
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
adapter.commitQuery(data);
|
||||
// scroll to the top of the list
|
||||
mLists[adapter.getMediaType() - 1].setSelection(0);
|
||||
}
|
||||
});
|
||||
mRequeryNeeded[adapter.getMediaType() - 1] = false;
|
||||
break;
|
||||
}
|
||||
case MSG_SAVE_SORT: {
|
||||
MediaAdapter adapter = (MediaAdapter)message.obj;
|
||||
SharedPreferences.Editor editor = PlaybackService.getSettings(this).edit();
|
||||
editor.putInt(String.format("sort_%d_%d", adapter.getMediaType(), adapter.getLimiterType()), adapter.getSortMode());
|
||||
editor.commit();
|
||||
break;
|
||||
}
|
||||
case MSG_REQUEST_REQUERY:
|
||||
requestRequery((LibraryAdapter)message.obj);
|
||||
break;
|
||||
default:
|
||||
return super.handleMessage(message);
|
||||
}
|
||||
@ -1186,56 +927,10 @@ public class LibraryActivity
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requery the given adapter. If it is the current adapter, requery
|
||||
* immediately. Otherwise, mark the adapter as needing a requery and requery
|
||||
* when its tab is selected.
|
||||
*
|
||||
* Must be called on the UI thread.
|
||||
*/
|
||||
public void requestRequery(LibraryAdapter adapter)
|
||||
{
|
||||
if (adapter == mCurrentAdapter) {
|
||||
runQuery(adapter);
|
||||
} else {
|
||||
mRequeryNeeded[adapter.getMediaType() - 1] = true;
|
||||
// Clear the data for non-visible adapters (so we don't show the old
|
||||
// data briefly when we later switch to that adapter)
|
||||
adapter.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule a query to be run for the given adapter on the worker thread.
|
||||
*
|
||||
* @param adapter The adapter to run the query for.
|
||||
*/
|
||||
private void runQuery(LibraryAdapter adapter)
|
||||
{
|
||||
mHandler.removeMessages(MSG_RUN_QUERY, adapter);
|
||||
mHandler.sendMessage(mHandler.obtainMessage(MSG_RUN_QUERY, adapter));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMediaChange()
|
||||
{
|
||||
for (LibraryAdapter adapter : mAdapters) {
|
||||
if (adapter != null) {
|
||||
postRequestRequery(adapter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call {@link LibraryActivity#requestRequery(LibraryAdapter)} on the UI
|
||||
* thread.
|
||||
*
|
||||
* @param adapter The adapter, passed to requestRequery.
|
||||
*/
|
||||
public void postRequestRequery(LibraryAdapter adapter)
|
||||
{
|
||||
Handler handler = mUiHandler;
|
||||
handler.sendMessage(handler.obtainMessage(MSG_REQUEST_REQUERY, adapter));
|
||||
mPagerAdapter.invalidateData();
|
||||
}
|
||||
|
||||
private void setSearchBoxVisible(boolean visible)
|
||||
@ -1313,20 +1008,6 @@ public class LibraryActivity
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the saved sort mode for the given adapter. The adapter should
|
||||
* be re-queried after calling this.
|
||||
*
|
||||
* @param adapter The adapter to load for.
|
||||
*/
|
||||
public void loadSortOrder(MediaAdapter adapter)
|
||||
{
|
||||
String key = String.format("sort_%d_%d", adapter.getMediaType(), adapter.getLimiterType());
|
||||
int def = adapter.getDefaultSortMode();
|
||||
int sort = PlaybackService.getSettings(this).getInt(key, def);
|
||||
adapter.setSortMode(sort);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which)
|
||||
{
|
||||
@ -1336,8 +1017,6 @@ public class LibraryActivity
|
||||
@Override
|
||||
public void onDismiss(DialogInterface dialog)
|
||||
{
|
||||
MediaAdapter adapter = (MediaAdapter)mCurrentAdapter;
|
||||
|
||||
ListView list = ((AlertDialog)dialog).getListView();
|
||||
// subtract 1 for header
|
||||
int which = list.getCheckedItemPosition() - 1;
|
||||
@ -1346,54 +1025,21 @@ public class LibraryActivity
|
||||
if (group.getCheckedRadioButtonId() == R.id.descending)
|
||||
which = ~which;
|
||||
|
||||
adapter.setSortMode(which);
|
||||
requestRequery(adapter);
|
||||
|
||||
// Force a new FastScroller to be created so the scroll sections
|
||||
// are updated.
|
||||
ListView view = mLists[mViewPager.getCurrentItem()];
|
||||
view.setFastScrollEnabled(false);
|
||||
view.setFastScrollEnabled(true);
|
||||
|
||||
mHandler.sendMessage(mHandler.obtainMessage(MSG_SAVE_SORT, adapter));
|
||||
mPagerAdapter.setSortMode(which);
|
||||
}
|
||||
|
||||
/**
|
||||
* Requery the adapter at the given position if it exists and needs a requery.
|
||||
* Called when a new adapter has been made visible.
|
||||
*
|
||||
* @param position An index in mAdapters.
|
||||
* @param adapter The new visible adapter.
|
||||
*/
|
||||
public void requeryIfNeeded(int position)
|
||||
public void onAdapterSelected(LibraryAdapter adapter)
|
||||
{
|
||||
LibraryAdapter adapter = mAdapters[position];
|
||||
if (adapter != null && mRequeryNeeded[position]) {
|
||||
runQuery(adapter);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrollStateChanged(int arg0)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrolled(int arg0, float arg1, int arg2)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageSelected(int position)
|
||||
{
|
||||
mCurrentAdapter = mAdapters[position];
|
||||
requeryIfNeeded(position);
|
||||
if (position < ADAPTER_COUNT - 1)
|
||||
requeryIfNeeded(position + 1);
|
||||
if (position > 0)
|
||||
requeryIfNeeded(position - 1);
|
||||
mCurrentAdapter = adapter;
|
||||
mLastActedId = -2;
|
||||
updateLimiterViews();
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
|
||||
CompatHoneycomb.selectTab(this, position);
|
||||
CompatHoneycomb.selectTab(this, mViewPager.getCurrentItem());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
635
src/org/kreed/vanilla/LibraryPagerAdapter.java
Normal file
635
src/org/kreed/vanilla/LibraryPagerAdapter.java
Normal file
@ -0,0 +1,635 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Christopher Eby <kreed@kreed.org>
|
||||
*
|
||||
* 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 org.kreed.vanilla;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.database.ContentObserver;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.Parcelable;
|
||||
import android.provider.MediaStore;
|
||||
import android.support.v4.view.PagerAdapter;
|
||||
import android.support.v4.view.ViewPager;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ListView;
|
||||
|
||||
/**
|
||||
* PagerAdapter that manages the library media ListViews.
|
||||
*/
|
||||
public class LibraryPagerAdapter extends PagerAdapter implements Handler.Callback, ViewPager.OnPageChangeListener {
|
||||
/**
|
||||
* The number of adapters/lists (determines array sizes).
|
||||
*/
|
||||
private static final int ADAPTER_COUNT = 6;
|
||||
/**
|
||||
* The human-readable title for each page.
|
||||
*/
|
||||
private static final int[] TITLES = { R.string.artists, R.string.albums, R.string.songs,
|
||||
R.string.playlists, R.string.genres, R.string.files };
|
||||
|
||||
/**
|
||||
* The ListView for each adapter, in the same order as MediaUtils.TYPE_*.
|
||||
*/
|
||||
private final ListView[] mLists = new ListView[ADAPTER_COUNT];
|
||||
/**
|
||||
* Whether the adapter corresponding to each index has stale data.
|
||||
*/
|
||||
private final boolean[] mRequeryNeeded = new boolean[ADAPTER_COUNT];
|
||||
/**
|
||||
* Each adapter, in the same order as MediaUtils.TYPE_*.
|
||||
*/
|
||||
public final LibraryAdapter[] mAdapters = new LibraryAdapter[ADAPTER_COUNT];
|
||||
/**
|
||||
* The artist adapter instance, also stored at mAdapters[0].
|
||||
*/
|
||||
private MediaAdapter mArtistAdapter;
|
||||
/**
|
||||
* The album adapter instance, also stored at mAdapters[1].
|
||||
*/
|
||||
private MediaAdapter mAlbumAdapter;
|
||||
/**
|
||||
* The song adapter instance, also stored at mAdapters[2].
|
||||
*/
|
||||
private MediaAdapter mSongAdapter;
|
||||
/**
|
||||
* The playlist adapter instance, also stored at mAdapters[3].
|
||||
*/
|
||||
private MediaAdapter mPlaylistAdapter;
|
||||
/**
|
||||
* The file adapter instance, also stored at mAdapters[5].
|
||||
*/
|
||||
private FileSystemAdapter mFilesAdapter;
|
||||
/**
|
||||
* The adapter of the currently visible list.
|
||||
*/
|
||||
private LibraryAdapter mCurrentAdapter;
|
||||
/**
|
||||
* The index of the current page.
|
||||
*/
|
||||
private int mCurrentPage;
|
||||
/**
|
||||
* A limiter that should be set when the album adapter is created.
|
||||
*/
|
||||
private Limiter mPendingAlbumLimiter;
|
||||
/**
|
||||
* A limiter that should be set when the song adapter is created.
|
||||
*/
|
||||
private Limiter mPendingSongLimiter;
|
||||
/**
|
||||
* A limiter that should be set when the files adapter is created.
|
||||
*/
|
||||
private Limiter mPendingFileLimiter;
|
||||
/**
|
||||
* List positions stored in the saved state, or null if none were stored.
|
||||
*/
|
||||
private int[] mSavedPositions;
|
||||
/**
|
||||
* The LibraryActivity that owns this adapter. The adapter will be notified
|
||||
* of changes in the current page.
|
||||
*/
|
||||
private final LibraryActivity mActivity;
|
||||
/**
|
||||
* A Handler running on the UI thread.
|
||||
*/
|
||||
private final Handler mUiHandler;
|
||||
/**
|
||||
* A Handler runing on a worker thread.
|
||||
*/
|
||||
private final Handler mWorkerHandler;
|
||||
/**
|
||||
* The text to be displayed in the first row of the artist, album, and
|
||||
* song limiters.
|
||||
*/
|
||||
private String mHeaderText;
|
||||
/**
|
||||
* The current filter text, or null if none.
|
||||
*/
|
||||
private String mFilter;
|
||||
|
||||
private final ContentObserver mPlaylistObserver = new ContentObserver(null) {
|
||||
@Override
|
||||
public void onChange(boolean selfChange)
|
||||
{
|
||||
if (mPlaylistAdapter != null) {
|
||||
postRequestRequery(mPlaylistAdapter);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Create the LibraryPager.
|
||||
*
|
||||
* @param activity The LibraryActivity that will own this adapter. The activity
|
||||
* will receive callbacks from the ListViews.
|
||||
* @param workerLooper A Looper running on a worker thread.
|
||||
*/
|
||||
public LibraryPagerAdapter(LibraryActivity activity, Looper workerLooper)
|
||||
{
|
||||
mActivity = activity;
|
||||
mUiHandler = new Handler(this);
|
||||
mWorkerHandler = new Handler(workerLooper, this);
|
||||
mCurrentPage = -1;
|
||||
activity.getContentResolver().registerContentObserver(MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI, true, mPlaylistObserver);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object instantiateItem(ViewGroup container, int position)
|
||||
{
|
||||
ListView view = mLists[position];
|
||||
|
||||
if (view == null) {
|
||||
LibraryActivity activity = mActivity;
|
||||
LibraryAdapter adapter;
|
||||
|
||||
switch (position) {
|
||||
case 0:
|
||||
adapter = mArtistAdapter = new MediaAdapter(activity, MediaUtils.TYPE_ARTIST, true, true, null);
|
||||
mArtistAdapter.setHeaderText(mHeaderText);
|
||||
break;
|
||||
case 1:
|
||||
adapter = mAlbumAdapter = new MediaAdapter(activity, MediaUtils.TYPE_ALBUM, true, true, mPendingAlbumLimiter);
|
||||
mPendingAlbumLimiter = null;
|
||||
mAlbumAdapter.setHeaderText(mHeaderText);
|
||||
break;
|
||||
case 2:
|
||||
adapter = mSongAdapter = new MediaAdapter(activity, MediaUtils.TYPE_SONG, false, true, mPendingSongLimiter);
|
||||
mPendingSongLimiter = null;
|
||||
mSongAdapter.setHeaderText(mHeaderText);
|
||||
break;
|
||||
case 3:
|
||||
adapter = mPlaylistAdapter = new MediaAdapter(activity, MediaUtils.TYPE_PLAYLIST, true, false, null);
|
||||
break;
|
||||
case 4:
|
||||
adapter = new MediaAdapter(activity, MediaUtils.TYPE_GENRE, true, false, null);
|
||||
break;
|
||||
case 5:
|
||||
adapter = mFilesAdapter = new FileSystemAdapter(activity, mPendingFileLimiter);
|
||||
mPendingFileLimiter = null;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid position: " + position);
|
||||
}
|
||||
|
||||
view = new ListView(activity);
|
||||
view.setOnItemClickListener(activity);
|
||||
view.setOnCreateContextMenuListener(activity);
|
||||
view.setDivider(null);
|
||||
view.setFastScrollEnabled(true);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
|
||||
CompatHoneycomb.setFastScrollAlwaysVisible(view, true);
|
||||
}
|
||||
view.setScrollBarStyle(View.SCROLLBARS_OUTSIDE_INSET);
|
||||
|
||||
view.setAdapter(adapter);
|
||||
if (position != 5)
|
||||
loadSortOrder((MediaAdapter)adapter);
|
||||
|
||||
adapter.setFilter(mFilter);
|
||||
|
||||
mAdapters[position] = adapter;
|
||||
mLists[position] = view;
|
||||
mRequeryNeeded[position] = true;
|
||||
}
|
||||
|
||||
requeryIfNeeded(position);
|
||||
container.addView(view);
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyItem(ViewGroup container, int position, Object object)
|
||||
{
|
||||
container.removeView(mLists[position]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getPageTitle(int position)
|
||||
{
|
||||
return mActivity.getResources().getText(TITLES[position]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount()
|
||||
{
|
||||
return ADAPTER_COUNT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isViewFromObject(View view, Object object)
|
||||
{
|
||||
return view == object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPrimaryItem(ViewGroup container, int position, Object object)
|
||||
{
|
||||
LibraryAdapter adapter = mAdapters[position];
|
||||
if (adapter != mCurrentAdapter) {
|
||||
requeryIfNeeded(position);
|
||||
mCurrentAdapter = adapter;
|
||||
mCurrentPage = position;
|
||||
mActivity.onAdapterSelected(adapter);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreState(Parcelable state, ClassLoader loader)
|
||||
{
|
||||
Bundle in = (Bundle)state;
|
||||
mPendingAlbumLimiter = (Limiter)in.getSerializable("limiter_albums");
|
||||
mPendingSongLimiter = (Limiter)in.getSerializable("limiter_songs");
|
||||
mPendingFileLimiter = (Limiter)in.getSerializable("limiter_files");
|
||||
mSavedPositions = in.getIntArray("pos");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parcelable saveState()
|
||||
{
|
||||
Bundle out = new Bundle(10);
|
||||
if (mAlbumAdapter != null)
|
||||
out.putSerializable("limiter_albums", mAlbumAdapter.getLimiter());
|
||||
if (mSongAdapter != null)
|
||||
out.putSerializable("limiter_songs", mSongAdapter.getLimiter());
|
||||
if (mFilesAdapter != null)
|
||||
out.putSerializable("limiter_files", mFilesAdapter.getLimiter());
|
||||
|
||||
int[] savedPositions = new int[ADAPTER_COUNT];
|
||||
ListView[] lists = mLists;
|
||||
for (int i = ADAPTER_COUNT; --i != -1; ) {
|
||||
if (lists[i] != null) {
|
||||
savedPositions[i] = lists[i].getFirstVisiblePosition();
|
||||
}
|
||||
}
|
||||
out.putIntArray("pos", savedPositions);
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the text to be displayed in the first row of the artist, album, and
|
||||
* song lists.
|
||||
*/
|
||||
public void setHeaderText(String text)
|
||||
{
|
||||
if (mArtistAdapter != null)
|
||||
mArtistAdapter.setHeaderText(text);
|
||||
if (mAlbumAdapter != null)
|
||||
mAlbumAdapter.setHeaderText(text);
|
||||
if (mSongAdapter != null)
|
||||
mSongAdapter.setHeaderText(text);
|
||||
mHeaderText = text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear a limiter.
|
||||
*
|
||||
* @param type Which type of limiter to clear.
|
||||
*/
|
||||
public void clearLimiter(int type)
|
||||
{
|
||||
if (type == MediaUtils.TYPE_FILE) {
|
||||
if (mFilesAdapter == null) {
|
||||
mPendingFileLimiter = null;
|
||||
} else {
|
||||
mFilesAdapter.setLimiter(null);
|
||||
requestRequery(mFilesAdapter);
|
||||
}
|
||||
} else {
|
||||
if (mAlbumAdapter == null) {
|
||||
mPendingAlbumLimiter = null;
|
||||
} else {
|
||||
mAlbumAdapter.setLimiter(null);
|
||||
loadSortOrder(mAlbumAdapter);
|
||||
requestRequery(mAlbumAdapter);
|
||||
}
|
||||
if (mSongAdapter == null) {
|
||||
mPendingSongLimiter = null;
|
||||
} else {
|
||||
mSongAdapter.setLimiter(null);
|
||||
loadSortOrder(mSongAdapter);
|
||||
requestRequery(mSongAdapter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the adapters with the given limiter.
|
||||
*
|
||||
* @param limiter The limiter to set.
|
||||
* @return The tab appropriate for expanding a row.
|
||||
*/
|
||||
public int setLimiter(Limiter limiter)
|
||||
{
|
||||
int tab;
|
||||
|
||||
switch (limiter.type) {
|
||||
case MediaUtils.TYPE_ALBUM:
|
||||
if (mSongAdapter == null) {
|
||||
mPendingSongLimiter = limiter;
|
||||
} else {
|
||||
mSongAdapter.setLimiter(limiter);
|
||||
loadSortOrder(mSongAdapter);
|
||||
requestRequery(mSongAdapter);
|
||||
}
|
||||
tab = 2;
|
||||
break;
|
||||
case MediaUtils.TYPE_ARTIST:
|
||||
if (mAlbumAdapter == null) {
|
||||
mPendingAlbumLimiter = limiter;
|
||||
} else {
|
||||
mAlbumAdapter.setLimiter(limiter);
|
||||
loadSortOrder(mAlbumAdapter);
|
||||
requestRequery(mAlbumAdapter);
|
||||
}
|
||||
if (mSongAdapter == null) {
|
||||
mPendingSongLimiter = limiter;
|
||||
} else {
|
||||
mSongAdapter.setLimiter(limiter);
|
||||
loadSortOrder(mSongAdapter);
|
||||
requestRequery(mSongAdapter);
|
||||
}
|
||||
tab = 1;
|
||||
break;
|
||||
case MediaUtils.TYPE_GENRE:
|
||||
if (mAlbumAdapter == null) {
|
||||
mPendingAlbumLimiter = limiter;
|
||||
} else {
|
||||
mAlbumAdapter.setLimiter(limiter);
|
||||
loadSortOrder(mAlbumAdapter);
|
||||
requestRequery(mAlbumAdapter);
|
||||
}
|
||||
if (mSongAdapter == null) {
|
||||
mPendingSongLimiter = null;
|
||||
} else {
|
||||
mSongAdapter.setLimiter(limiter);
|
||||
loadSortOrder(mSongAdapter);
|
||||
requestRequery(mSongAdapter);
|
||||
}
|
||||
tab = 2;
|
||||
break;
|
||||
case MediaUtils.TYPE_FILE:
|
||||
if (mFilesAdapter == null) {
|
||||
mPendingFileLimiter = limiter;
|
||||
} else {
|
||||
mFilesAdapter.setLimiter(limiter);
|
||||
requestRequery(mFilesAdapter);
|
||||
}
|
||||
tab = 5;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported limiter type: " + limiter.type);
|
||||
}
|
||||
|
||||
return tab;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the limiter set on the current adapter or null if there is none.
|
||||
*/
|
||||
public Limiter getCurrentLimiter()
|
||||
{
|
||||
LibraryAdapter current = mCurrentAdapter;
|
||||
if (current == null)
|
||||
return null;
|
||||
return current.getLimiter();
|
||||
}
|
||||
|
||||
/**
|
||||
* Run on query on the adapter passed in obj.
|
||||
*
|
||||
* Runs on worker thread.
|
||||
*/
|
||||
private static final int MSG_RUN_QUERY = 0;
|
||||
/**
|
||||
* Save the sort mode for the adapter passed in obj.
|
||||
*
|
||||
* Runs on worker thread.
|
||||
*/
|
||||
private static final int MSG_SAVE_SORT = 1;
|
||||
/**
|
||||
* Call {@link LibraryActivity#requestRequery(LibraryAdapter)} on the adapter
|
||||
* passed in obj.
|
||||
*
|
||||
* Runs on worker thread.
|
||||
*/
|
||||
private static final int MSG_REQUEST_REQUERY = 2;
|
||||
/**
|
||||
* Commit the cursor passed in obj to the adapter at the index passed in
|
||||
* arg1.
|
||||
*
|
||||
* Runs on UI thread.
|
||||
*/
|
||||
private static final int MSG_COMMIT_QUERY = 3;
|
||||
|
||||
@Override
|
||||
public boolean handleMessage(Message message)
|
||||
{
|
||||
switch (message.what) {
|
||||
case MSG_RUN_QUERY: {
|
||||
LibraryAdapter adapter = (LibraryAdapter)message.obj;
|
||||
int index = adapter.getMediaType() - 1;
|
||||
Handler handler = mUiHandler;
|
||||
handler.sendMessage(handler.obtainMessage(MSG_COMMIT_QUERY, index, 0, adapter.query()));
|
||||
break;
|
||||
}
|
||||
case MSG_COMMIT_QUERY: {
|
||||
int index = message.arg1;
|
||||
mAdapters[index].commitQuery(message.obj);
|
||||
int pos;
|
||||
if (mSavedPositions == null) {
|
||||
pos = 0;
|
||||
} else {
|
||||
pos = mSavedPositions[index];
|
||||
mSavedPositions[index] = 0;
|
||||
}
|
||||
mLists[index].setSelection(pos);
|
||||
break;
|
||||
}
|
||||
case MSG_SAVE_SORT: {
|
||||
MediaAdapter adapter = (MediaAdapter)message.obj;
|
||||
SharedPreferences.Editor editor = PlaybackService.getSettings(mActivity).edit();
|
||||
editor.putInt(String.format("sort_%d_%d", adapter.getMediaType(), adapter.getLimiterType()), adapter.getSortMode());
|
||||
editor.commit();
|
||||
break;
|
||||
}
|
||||
case MSG_REQUEST_REQUERY:
|
||||
requestRequery((LibraryAdapter)message.obj);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requery the given adapter. If it is the current adapter, requery
|
||||
* immediately. Otherwise, mark the adapter as needing a requery and requery
|
||||
* when its tab is selected.
|
||||
*
|
||||
* Must be called on the UI thread.
|
||||
*/
|
||||
public void requestRequery(LibraryAdapter adapter)
|
||||
{
|
||||
if (adapter == mCurrentAdapter) {
|
||||
postRunQuery(adapter);
|
||||
} else {
|
||||
mRequeryNeeded[adapter.getMediaType() - 1] = true;
|
||||
// Clear the data for non-visible adapters (so we don't show the old
|
||||
// data briefly when we later switch to that adapter)
|
||||
adapter.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call {@link LibraryActivity#requestRequery(LibraryAdapter)} on the UI
|
||||
* thread.
|
||||
*
|
||||
* @param adapter The adapter, passed to requestRequery.
|
||||
*/
|
||||
public void postRequestRequery(LibraryAdapter adapter)
|
||||
{
|
||||
Handler handler = mUiHandler;
|
||||
handler.sendMessage(handler.obtainMessage(MSG_REQUEST_REQUERY, adapter));
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule a query to be run for the given adapter on the worker thread.
|
||||
*
|
||||
* @param adapter The adapter to run the query for.
|
||||
*/
|
||||
private void postRunQuery(LibraryAdapter adapter)
|
||||
{
|
||||
mRequeryNeeded[adapter.getMediaType() - 1] = false;
|
||||
Handler handler = mWorkerHandler;
|
||||
handler.removeMessages(MSG_RUN_QUERY, adapter);
|
||||
handler.sendMessage(handler.obtainMessage(MSG_RUN_QUERY, adapter));
|
||||
}
|
||||
|
||||
/**
|
||||
* Requery the adapter at the given position if it exists and needs a requery.
|
||||
*
|
||||
* @param position An index in mAdapters.
|
||||
*/
|
||||
private void requeryIfNeeded(int position)
|
||||
{
|
||||
LibraryAdapter adapter = mAdapters[position];
|
||||
if (adapter != null && mRequeryNeeded[position]) {
|
||||
postRunQuery(adapter);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate the data for all adapters.
|
||||
*/
|
||||
public void invalidateData()
|
||||
{
|
||||
for (LibraryAdapter adapter : mAdapters) {
|
||||
if (adapter != null) {
|
||||
postRequestRequery(adapter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the saved sort mode for the given adapter. The adapter should
|
||||
* be re-queried after calling this.
|
||||
*
|
||||
* @param adapter The adapter to load for.
|
||||
*/
|
||||
public void loadSortOrder(MediaAdapter adapter)
|
||||
{
|
||||
String key = String.format("sort_%d_%d", adapter.getMediaType(), adapter.getLimiterType());
|
||||
int def = adapter.getDefaultSortMode();
|
||||
int sort = PlaybackService.getSettings(mActivity).getInt(key, def);
|
||||
adapter.setSortMode(sort);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the sort mode for the current adapter. Current adapter must be a
|
||||
* MediaAdapter. Saves this sort mode to preferences and updates the list
|
||||
* associated with the adapter to display the new sort mode.
|
||||
*
|
||||
* @param mode The sort mode. See {@link MediaAdapter#setSortMode(int)} for
|
||||
* details.
|
||||
*/
|
||||
public void setSortMode(int mode)
|
||||
{
|
||||
MediaAdapter adapter = (MediaAdapter)mCurrentAdapter;
|
||||
|
||||
adapter.setSortMode(mode);
|
||||
requestRequery(adapter);
|
||||
|
||||
// Force a new FastScroller to be created so the scroll sections
|
||||
// are updated.
|
||||
ListView view = mLists[mCurrentPage];
|
||||
view.setFastScrollEnabled(false);
|
||||
view.setFastScrollEnabled(true);
|
||||
|
||||
Handler handler = mWorkerHandler;
|
||||
handler.sendMessage(handler.obtainMessage(MSG_SAVE_SORT, adapter));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a new filter on all the adapters.
|
||||
*/
|
||||
public void setFilter(String text)
|
||||
{
|
||||
if (text.length() == 0)
|
||||
text = null;
|
||||
|
||||
mFilter = text;
|
||||
for (LibraryAdapter adapter : mAdapters) {
|
||||
if (adapter != null) {
|
||||
adapter.setFilter(text);
|
||||
requestRequery(adapter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrollStateChanged(int state)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageSelected(int position)
|
||||
{
|
||||
// onPageSelected and setPrimaryItem are called in similar cases, and it
|
||||
// would be nice to use just one of them, but each has caveats:
|
||||
// - onPageSelected isn't called when the ViewPager is first
|
||||
// initialized
|
||||
// - setPrimaryItem isn't called until scrolling is complete, which
|
||||
// makes tab bar and limiter updates look bad
|
||||
// So we use both.
|
||||
setPrimaryItem(null, position, null);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user