mp.teardrop.LibraryPagerAdapter.java Source code

Java tutorial

Introduction

Here is the source code for mp.teardrop.LibraryPagerAdapter.java

Source

/*
 * 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 mp.teardrop;

import java.util.ArrayList;
import java.util.Arrays;

import android.content.Intent;
import android.content.SharedPreferences;
import android.database.ContentObserver;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.TextView;

/**
 * PagerAdapter that manages the library media ListViews.
 */
public class LibraryPagerAdapter extends PagerAdapter implements Handler.Callback, ViewPager.OnPageChangeListener,
        View.OnCreateContextMenuListener, AdapterView.OnItemClickListener {
    /**
     * The number of unique list types. The number of visible lists may be
     * smaller.
     */
    public static final int MAX_ADAPTER_COUNT = 3;
    /**
     * The human-readable title for each list. The positions correspond to the
     * MediaUtils ids, so e.g. TITLES[MediaUtils.TYPE_SONG] = R.string.songs
     */
    public static final int[] TITLES = { R.string.files, R.string.local_library, R.string.dropbox };
    /**
     * Default tab order.
     */
    public static final int[] DEFAULT_ORDER = { MediaUtils.TYPE_DROPBOX, MediaUtils.TYPE_FILE,
            MediaUtils.TYPE_UNIFIED };
    /**
     * The user-chosen tab order.
     */
    int[] mTabOrder;
    /**
     * The number of visible tabs.
     */
    private int mTabCount;
    /**
     * The LinearLayout containing the ListView for each adapter. Each index corresponds to that list's
     * MediaUtils id.
     */
    final ViewGroup[] mContainingLayouts = new ViewGroup[MAX_ADAPTER_COUNT];
    /**
     * The adapters. Each index corresponds to that adapter's MediaUtils id.
     */
    public LibraryAdapter[] mAdapters = new LibraryAdapter[MAX_ADAPTER_COUNT];
    /**
     * Whether the adapter corresponding to each index has stale data.
     */
    private final boolean[] mRequeryNeeded = new boolean[MAX_ADAPTER_COUNT];
    /**
     * The file adapter instance, also stored at mAdapters[MediaUtils.TYPE_FILE].
     */
    FileSystemAdapter mFilesAdapter;
    /**
     * A back stack of limiters for the file adapter, used to handle back key presses.
     */
    private ArrayList<Limiter> mFilesAdapterBackStack = new ArrayList<Limiter>();
    /**
     * A back stack of limiters for the Dropbox adapter, used to handle back key presses.
     */
    private ArrayList<Limiter> mDropboxAdapterBackStack = new ArrayList<Limiter>();
    /**
     * The local library adapter instance, also stored at mAdapters[MediaUtils.TYPE_UNIFIED].
     */
    UnifiedAdapter mUnifiedAdapter;
    /**
     * The Dropbox adapter instance, also stored at mAdapters[MediaUtils.TYPE_UNIFIED].
     */
    DropboxAdapter mDropboxAdapter;
    /**
     * A back stack of limiters for the local library adapter, used to handle back key presses.
     */
    private ArrayList<Limiter> mUnifiedAdapterBackStack = new ArrayList<Limiter>();
    /**
     * The adapter of the currently visible list.
     */
    private LibraryAdapter mCurrentAdapter;
    /**
     * The index of the current page.
     */
    int mCurrentPage;
    /**
     * 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 running 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;
    private TextView mArtistHeader;
    private TextView mAlbumHeader;
    private TextView mSongHeader;
    /**
     * The current filter text, or null if none.
     */
    private String mFilter;
    /**
     * The position of the songs page, or -1 if it is hidden.
     */
    public int mSongsPosition = -1;
    /**
     * The position of the albums page, or -1 if it is hidden.
     */
    public int mAlbumsPosition = -1;
    /**
     * The position of the artists page, or -1 if it is hidden.
     */
    public int mArtistsPosition = -1;
    /**
     * The position of the genres page, or -1 if it is hidden.
     */
    public int mGenresPosition = -1;

    private HorizontalScrollView mLimiterScroller;

    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);
    }

    /**
     * Load the tab order from SharedPreferences.
     *
     * @return True if order has changed.
     */
    public boolean loadTabOrder() {
        String in = PlaybackService.getSettings(mActivity).getString(PrefKeys.TAB_ORDER, null);
        int[] order;
        int count;
        if (in == null || in.length() != MAX_ADAPTER_COUNT) {
            order = DEFAULT_ORDER;
            count = MAX_ADAPTER_COUNT;
        } else {
            char[] chars = in.toCharArray();
            order = new int[MAX_ADAPTER_COUNT];
            count = 0;
            for (int i = 0; i != MAX_ADAPTER_COUNT; ++i) {
                char v = chars[i];
                if (v >= 128) {
                    v -= 128;
                    if (v >= MediaUtils.TYPE_COUNT) {
                        // invalid media type; use default order
                        order = DEFAULT_ORDER;
                        count = MAX_ADAPTER_COUNT;
                        break;
                    }
                    order[count++] = v;
                }
            }
        }

        if (count != mTabCount || !Arrays.equals(order, mTabOrder)) {
            mTabOrder = order;
            mTabCount = count;
            notifyDataSetChanged();
            computeExpansions();
            return true;
        }

        return false;
    }

    /**
     * Determines whether adapters should be expandable from the visibility of
     * the adapters each expands to. Also updates mSongsPosition/mAlbumsPositions.
     */
    public void computeExpansions() {
        int[] order = mTabOrder;
        int songsPosition = -1;
        int albumsPosition = -1;
        int artistsPosition = -1;
        int genresPosition = -1;
        for (int i = mTabCount; --i != -1;) {
            /* switch (order[i]) {
            case MediaUtils.TYPE_ALBUM:
               albumsPosition = i;
               break;
            case MediaUtils.TYPE_SONG:
               songsPosition = i;
               break;
            case MediaUtils.TYPE_ARTIST:
               artistsPosition = i;
               break;
            case MediaUtils.TYPE_GENRE:
               genresPosition = i;
               break;
            } */
        }

        /* if (mArtistAdapter != null)
           mArtistAdapter.setExpandable(songsPosition != -1 || albumsPosition != -1);
        if (mAlbumAdapter != null)
           mAlbumAdapter.setExpandable(songsPosition != -1);
        if (mGenreAdapter != null)
           mGenreAdapter.setExpandable(songsPosition != -1); */

        mSongsPosition = songsPosition;
        mAlbumsPosition = albumsPosition;
        mArtistsPosition = artistsPosition;
        mGenresPosition = genresPosition;
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        final int type = mTabOrder[position];
        ViewGroup containingLayout = mContainingLayouts[type];

        if (containingLayout == null) {
            LibraryActivity activity = mActivity;
            LayoutInflater inflater = activity.getLayoutInflater();
            LibraryAdapter adapter;

            containingLayout = (RelativeLayout) inflater.inflate(R.layout.listview, null);

            switch (type) {
            case MediaUtils.TYPE_FILE:
                adapter = mFilesAdapter = new FileSystemAdapter(activity, null);
                break;
            case MediaUtils.TYPE_UNIFIED:
                adapter = mUnifiedAdapter = new UnifiedAdapter(activity, null);
                break;
            case MediaUtils.TYPE_DROPBOX:
                adapter = mDropboxAdapter = new DropboxAdapter(activity, null);
                //if linked with Dropbox, query the root
                //TODO: maybe use a field in activity or somewhere to save linked state instead of checking prefs here
                SharedPreferences prefs = activity.getSharedPreferences(LibraryActivity.ACCOUNT_PREFS_NAME, 0);
                String key = prefs.getString(LibraryActivity.ACCESS_KEY_NAME, null);
                String secret = prefs.getString(LibraryActivity.ACCESS_SECRET_NAME, null);

                /* if we're linked with Dropbox, show the loading message and retrieve the root
                   folder's contents */
                if (!(key == null || secret == null || key.length() == 0 || secret.length() == 0)) {

                    View screen = containingLayout.findViewById(R.id.list_view_loading_screen);
                    screen.setOnClickListener(new View.OnClickListener() { //will stick for the entire session
                        @Override
                        public void onClick(View v) {
                        }
                    });
                    screen.setVisibility(View.VISIBLE);

                    activity.requeryDropbox(null);
                }

                break;
            default:
                throw new IllegalArgumentException("Invalid media type: " + type);
            }

            mLimiterScroller = (HorizontalScrollView) containingLayout.findViewById(R.id.new_limiter_scroller);
            ListView view = (ListView) containingLayout.findViewById(R.id.actual_list_view);
            view.setOnCreateContextMenuListener(this);
            view.setOnItemClickListener(this);
            view.setTag(type);
            view.setAdapter(adapter);
            adapter.setFilter(mFilter);

            mAdapters[type] = adapter;
            mContainingLayouts[type] = containingLayout;

            mRequeryNeeded[type] = true;

        }

        requeryIfNeeded(type);
        container.addView(containingLayout);
        return containingLayout;
    }

    //TODO: this method turned into a mess, clean it up
    @Override
    public int getItemPosition(Object item) {
        if (item != null && ((View) item).getTag() != null) {
            int type = (Integer) ((View) item).getTag();
            int[] order = mTabOrder;
            for (int i = mTabCount; --i != -1;) {
                if (order[i] == type)
                    return i;
            }
        }
        return POSITION_NONE;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        container.removeView((View) object);
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return mActivity.getResources().getText(TITLES[mTabOrder[position]]);
    }

    @Override
    public int getCount() {
        return mTabCount;
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view == object;
    }

    @Override
    public void setPrimaryItem(ViewGroup container, int position, Object object) {
        int type = mTabOrder[position];
        LibraryAdapter adapter = mAdapters[type];

        if (adapter == null)
            return; //TODO: this is a hacky fix for a crash, try to get to the root of the problem

        if (position != mCurrentPage || adapter != mCurrentAdapter) {
            requeryIfNeeded(type);
            mCurrentAdapter = adapter;
            mCurrentPage = position;
            mActivity.onPageChanged(position, adapter);
        }
    }

    /**
     * Gets the type of items that are currently being displayed.
     * 
     * @return One of the values defined as constants in {@link MediaUtils}.
     */
    int getCurrentType() {
        return (mTabOrder[mCurrentPage]);
    }

    /**
     * Sets the text to be displayed in the first row of the artist, album, and
     * song lists.
     */
    public void setHeaderText(String text) {
        if (mArtistHeader != null)
            mArtistHeader.setText(text);
        if (mAlbumHeader != null)
            mAlbumHeader.setText(text);
        if (mSongHeader != null)
            mSongHeader.setText(text);
        mHeaderText = text;
    }

    /**
     * Clear a limiter.
     *
     * @param type Which type of limiter to clear.
     */
    public void clearLimiter(int type) {
        if (type == MediaUtils.TYPE_FILE) {
            mFilesAdapter.setLimiter(null);
            requestRequery(mFilesAdapter);
        } else if (type == MediaUtils.TYPE_UNIFIED || type > 10) {
            mUnifiedAdapter.setLimiter(null);
            requestRequery(mUnifiedAdapter);
        } else if (type == MediaUtils.TYPE_DROPBOX) {
            mActivity.requeryDropbox(null);
        }
    }

    /**
     * Update the current adapter with the given limiter.
     * The current limiter, even if null, is backed up
     * to mFilesAdapterBackStack or one of its counterparts
     * before being overwritten.
     *
     * @param limiter The limiter to set.
     */
    public void setLimiter(Limiter limiter) {
        int adapterType = getCurrentType();

        switch (adapterType) {
        case MediaUtils.TYPE_UNIFIED:
            mUnifiedAdapterBackStack.add(mUnifiedAdapter.getLimiter());
            mUnifiedAdapter.setLimiter(limiter);
            requestRequery(mUnifiedAdapter);
            break;
        case MediaUtils.TYPE_FILE:
            mFilesAdapterBackStack.add(mFilesAdapter.getLimiter());
            mFilesAdapter.setLimiter(limiter);
            requestRequery(mFilesAdapter);
            break;
        case MediaUtils.TYPE_DROPBOX:
            mDropboxAdapterBackStack.add(mDropboxAdapter.getLimiter());
            //mDropboxAdapter.setLimiter(limiter);
            mActivity.requeryDropbox(limiter);
        }
    }

    /**
     * Removes the last used limiter from the "back stack"
     * and re-applies it to this adapter.
     *
     * @return False if the back stack was empty (i.e. there's nothing to go back to), true otherwise.
     */
    public boolean goBackToPreviousLimiter() {
        if (getCurrentLimiter() == null)
            return false;

        int adapterType = getCurrentLimiter().type > 10 ? MediaUtils.TYPE_UNIFIED : getCurrentLimiter().type;

        switch (adapterType) {
        case MediaUtils.TYPE_UNIFIED:
            if (mUnifiedAdapterBackStack.isEmpty())
                return false;
            mUnifiedAdapter.setLimiter(mUnifiedAdapterBackStack.remove(mUnifiedAdapterBackStack.size() - 1));
            requestRequery(mUnifiedAdapter);
            return true;
        case MediaUtils.TYPE_FILE:
            if (mFilesAdapterBackStack.isEmpty())
                return false;
            mFilesAdapter.setLimiter(mFilesAdapterBackStack.remove(mFilesAdapterBackStack.size() - 1));
            requestRequery(mFilesAdapter);
            return true;
        case MediaUtils.TYPE_DROPBOX:
            if (mDropboxAdapterBackStack.isEmpty())
                return false;
            mActivity.requeryDropbox(mDropboxAdapterBackStack.remove(mDropboxAdapterBackStack.size() - 1));
            return true;
        default:
            return false;
        }
    }

    /**
     * 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 LibraryPagerAdapter#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: {
            //we are on the worker thread here
            LibraryAdapter adapter = (LibraryAdapter) message.obj;
            Handler handler = mUiHandler;
            handler.sendMessage(
                    handler.obtainMessage(MSG_COMMIT_QUERY, adapter.getMediaType(), 0, adapter.query()));
            break;
        }
        case MSG_COMMIT_QUERY: {
            //we are on the UI thread here
            int index = message.arg1;
            if (index == MediaUtils.TYPE_UNIFIED) {
                //MediaInfoHolder mih = (MediaInfoHolder) message.obj;
                mAdapters[index].commitQuery(message.obj);
                //showInLocalLibrary(mih);
            } else {
                mAdapters[index].commitQuery(message.obj);
                int pos;
                if (mSavedPositions == null) {
                    pos = 0;
                } else {
                    pos = mSavedPositions[index];
                    mSavedPositions[index] = 0;
                }
                ListView listView = (ListView) mContainingLayouts[index].findViewById(R.id.actual_list_view);
                listView.setSelection(pos);
            }
            ((ListView) mContainingLayouts[getCurrentType()].findViewById(R.id.actual_list_view))
                    .smoothScrollToPosition(0);
            ;
            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;
    }

    public void requeryLocalAdapters() {
        for (int i = 0; i < mTabCount; i++) {
            int type = mTabOrder[i];
            if (type != MediaUtils.TYPE_DROPBOX) {
                requestRequery(mAdapters[type]);
            }
        }
    }

    /**
     * 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()] = 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 LibraryPagerAdapter#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 != null ? adapter.getMediaType() : MediaUtils.TYPE_UNIFIED] = false;
        Handler handler = mWorkerHandler;
        handler.removeMessages(MSG_RUN_QUERY, adapter);
        handler.sendMessage(handler.obtainMessage(MSG_RUN_QUERY, adapter));
    }

    /**
     * Requery the adapter of the given type if it exists and needs a requery.
     *
     * @param type One of MediaUtils.TYPE_*
     */
    private void requeryIfNeeded(int type) {
        LibraryAdapter adapter = mAdapters[type];
        if (adapter != null && mRequeryNeeded[type]) {
            postRunQuery(adapter);
        }
    }

    /**
     * Invalidate the data for all adapters.
     */
    public void invalidateData() //TODO: make this handle the local library tab properly
    {
        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;
        if (mode == adapter.getSortMode())
            return;

        adapter.setSortMode(mode);
        requestRequery(adapter);

        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) {
        //TODO: doesn't this cause excess redrawing? investigate
        // 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);
    }

    /**
     * Creates the row data used by LibraryActivity.
     */
    private static Intent createHeaderIntent(View header) {
        int type = (Integer) header.getTag();
        Intent intent = new Intent();
        intent.putExtra(LibraryAdapter.DATA_ID, LibraryAdapter.HEADER_ID);
        intent.putExtra(LibraryAdapter.DATA_TYPE, type);
        return intent;
    }

    @Override
    public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfo) {
        AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
        View targetView = info.targetView;
        Intent intent = info.id == -1 ? createHeaderIntent(targetView) : mCurrentAdapter.createData(targetView);
        mActivity.onCreateContextMenu(menu, intent);
    }

    @Override
    public void onItemClick(AdapterView<?> list, View view, int position, long id) {
        Intent intent = id == -1 ? createHeaderIntent(view) : mCurrentAdapter.createData(view);
        mActivity.onItemClicked(intent);
    }

    void updateLimiterViews() {

        LinearLayout limiterViews = (LinearLayout) mContainingLayouts[mTabOrder[mCurrentPage]]
                .findViewById(R.id.new_limiter_layout);

        if (limiterViews == null) {
            return;
        }

        limiterViews.removeAllViews();

        Limiter limiterData = getCurrentLimiter();

        if (mTabOrder[mCurrentPage] == MediaUtils.TYPE_FILE || mTabOrder[mCurrentPage] == MediaUtils.TYPE_DROPBOX) { //always create an element representing the root directory
            TextView textView1 = (TextView) mActivity.getLayoutInflater().inflate(R.layout.limiter_text_view, null);
            textView1.setText(R.string.root_directory);
            textView1.setTag(LibraryActivity.TAG_DELIMITER_ROOT); //used to handle click event properly
            textView1.setOnClickListener(mActivity);
            limiterViews.addView(textView1);
            mLimiterScroller.setVisibility(View.VISIBLE);
        } else if (mTabOrder[mCurrentPage] == MediaUtils.TYPE_UNIFIED) {
            // always create a link to the root of the library
            TextView textView1 = (TextView) mActivity.getLayoutInflater().inflate(R.layout.limiter_text_view, null);
            textView1.setText(R.string.library);
            textView1.setTag(LibraryActivity.TAG_DELIMITER_ROOT); //used to handle click event properly
            textView1.setOnClickListener(mActivity);
            limiterViews.addView(textView1);

            //create a link to all albums, artists or songs if applicable
            if (limiterData != null && (limiterData.type != UnifiedAdapter.ITEM_TYPE_MORE_ALBUMS
                    && limiterData.type != UnifiedAdapter.ITEM_TYPE_MORE_ARTISTS
                    && limiterData.type != UnifiedAdapter.ITEM_TYPE_MORE_SONGS
                    && limiterData.type != UnifiedAdapter.ITEM_TYPE_MORE_PLAYLISTS)) {
                textView1 = (TextView) mActivity.getLayoutInflater().inflate(R.layout.limiter_text_view, null);
                textView1.setText(R.string.limiter_separator);
                textView1.setTextColor(0xa3ffffff);
                limiterViews.addView(textView1);

                textView1 = (TextView) mActivity.getLayoutInflater().inflate(R.layout.limiter_text_view, null);

                switch (limiterData.type) {
                case UnifiedAdapter.ITEM_TYPE_ARTIST:
                    textView1.setText(R.string.artists);
                    textView1.setTag(LibraryActivity.TAG_ARTISTS_ROOT);
                    break;
                case UnifiedAdapter.ITEM_TYPE_ALBUM:
                    textView1.setText(R.string.albums);
                    textView1.setTag(LibraryActivity.TAG_ALBUMS_ROOT);
                    break;
                case UnifiedAdapter.ITEM_TYPE_PLAYLIST:
                    textView1.setText(R.string.playlists);
                    textView1.setTag(LibraryActivity.TAG_PLAYLISTS_ROOT);
                    break;
                }

                textView1.setOnClickListener(mActivity);
                limiterViews.addView(textView1);
            }
        }

        if (limiterData != null) {
            String[] limiter = limiterData.names;

            for (int i = 0; i != limiter.length; ++i) {
                TextView textView = (TextView) mActivity.getLayoutInflater().inflate(R.layout.limiter_text_view,
                        null);
                textView.setText(R.string.limiter_separator);
                textView.setTextColor(0xa3ffffff);
                limiterViews.addView(textView);

                textView = (TextView) mActivity.getLayoutInflater().inflate(R.layout.limiter_text_view, null);
                textView.setText(limiter[i]);
                textView.setTag(i);
                textView.setOnClickListener(mActivity);
                limiterViews.addView(textView);
            }
        }

    }

}