org.videolan.vlc.gui.browser.BaseBrowserFragment.java Source code

Java tutorial

Introduction

Here is the source code for org.videolan.vlc.gui.browser.BaseBrowserFragment.java

Source

/**
 * **************************************************************************
 * BaseBrowserFragment.java
 * ****************************************************************************
 * Copyright  2015 VLC authors and VideoLAN
 * Author: Geoffrey Mtais
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 * ***************************************************************************
 */
package org.videolan.vlc.gui.browser;

import android.annotation.TargetApi;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Message;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.PopupMenu;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.util.SparseArray;
import android.view.ContextMenu;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import org.videolan.libvlc.Media;
import org.videolan.libvlc.util.AndroidUtil;
import org.videolan.libvlc.util.MediaBrowser;
import org.videolan.vlc.MediaLibrary;
import org.videolan.vlc.MediaWrapper;
import org.videolan.vlc.PlaybackServiceClient;
import org.videolan.vlc.R;
import org.videolan.vlc.VLCApplication;
import org.videolan.vlc.gui.SecondaryActivity;
import org.videolan.vlc.gui.dialogs.CommonDialogs;
import org.videolan.vlc.gui.DividerItemDecoration;
import org.videolan.vlc.gui.MainActivity;
import org.videolan.vlc.gui.SidebarAdapter;
import org.videolan.vlc.gui.video.VideoPlayerActivity;
import org.videolan.vlc.interfaces.IRefreshable;
import org.videolan.vlc.util.Util;
import org.videolan.vlc.util.VLCInstance;
import org.videolan.vlc.util.VLCRunnable;
import org.videolan.vlc.util.WeakHandler;
import org.videolan.vlc.widget.ContextMenuRecyclerView;
import org.videolan.vlc.widget.SwipeRefreshLayout;

import java.util.ArrayList;

public abstract class BaseBrowserFragment extends MediaBrowserFragment
        implements IRefreshable, MediaBrowser.EventListener, SwipeRefreshLayout.OnRefreshListener {
    protected static final String TAG = "VLC/BaseBrowserFragment";

    public static String ROOT = "smb";
    public static final String KEY_MRL = "key_mrl";
    public static final String KEY_MEDIA = "key_media";
    public static final String KEY_MEDIA_LIST = "key_media_list";
    public static final String KEY_POSITION = "key_list";

    protected BrowserFragmentHandler mHandler;
    protected MediaBrowser mMediaBrowser;
    protected ContextMenuRecyclerView mRecyclerView;
    protected BaseBrowserAdapter mAdapter;
    protected LinearLayoutManager mLayoutManager;
    protected TextView mEmptyView;
    public String mMrl;
    protected MediaWrapper mCurrentMedia;
    protected int mSavedPosition = -1, mFavorites = 0;
    public boolean mRoot;

    private SparseArray<ArrayList<MediaWrapper>> mMediaLists = new SparseArray<ArrayList<MediaWrapper>>();
    private ArrayList<MediaWrapper> mediaList;
    public int mCurrentParsedPosition = 0;

    protected abstract Fragment createFragment();

    protected abstract void browseRoot();

    protected abstract String getCategoryTitle();

    public BaseBrowserFragment() {
        mHandler = new BrowserFragmentHandler(this);
        mAdapter = new BaseBrowserAdapter(this);
    }

    public void onCreate(Bundle bundle) {
        super.onCreate(bundle);

        if (bundle == null)
            bundle = getArguments();
        if (bundle != null) {
            mediaList = bundle.getParcelableArrayList(KEY_MEDIA_LIST);
            if (mediaList != null)
                mAdapter.addAll(mediaList);
            mCurrentMedia = bundle.getParcelable(KEY_MEDIA);
            if (mCurrentMedia != null)
                mMrl = mCurrentMedia.getLocation();
            else
                mMrl = bundle.getString(KEY_MRL);
            mSavedPosition = bundle.getInt(KEY_POSITION);
        }
    }

    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.directory_browser, container, false);
        mRecyclerView = (ContextMenuRecyclerView) v.findViewById(R.id.network_list);
        mEmptyView = (TextView) v.findViewById(android.R.id.empty);
        mLayoutManager = new LinearLayoutManager(getActivity());
        mRecyclerView
                .addItemDecoration(new DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL_LIST));
        mRecyclerView.setLayoutManager(mLayoutManager);
        mRecyclerView.setAdapter(mAdapter);
        mRecyclerView.addOnScrollListener(mScrollListener);
        registerForContextMenu(mRecyclerView);

        mSwipeRefreshLayout = (SwipeRefreshLayout) v.findViewById(R.id.swipeLayout);
        mSwipeRefreshLayout.setColorSchemeResources(R.color.orange700);
        mSwipeRefreshLayout.setOnRefreshListener(this);
        return v;
    }

    @Override
    public void onStart() {
        super.onStart();
        mMediaBrowser = new MediaBrowser(VLCInstance.get(), this);
    }

    public void onStop() {
        super.onStop();
        releaseBrowser();
    }

    private void releaseBrowser() {
        if (mMediaBrowser != null) {
            mMediaBrowser.release();
            mMediaBrowser = null;
        }
    }

    public void onSaveInstanceState(Bundle outState) {
        outState.putString(KEY_MRL, mMrl);
        outState.putParcelable(KEY_MEDIA, mCurrentMedia);
        outState.putParcelableArrayList(KEY_MEDIA_LIST, mediaList);
        if (mRecyclerView != null) {
            outState.putInt(KEY_POSITION, mLayoutManager.findFirstCompletelyVisibleItemPosition());
        }
        super.onSaveInstanceState(outState);
    }

    public boolean isRootDirectory() {
        return mRoot;
    }

    public String getTitle() {
        if (mRoot)
            return getCategoryTitle();
        else
            return mCurrentMedia != null ? mCurrentMedia.getTitle() : mMrl;
    }

    @Override
    protected void display() {
        if (!mReadyToDisplay) {
            mReadyToDisplay = true;
            update();
            return;
        }
        updateDisplay();
    }

    public void goBack() {
        if (!mRoot)
            getActivity().getSupportFragmentManager().popBackStack();
        else
            getActivity().finish();
    }

    public void browse(MediaWrapper media, int position) {
        FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
        Fragment next = createFragment();
        Bundle args = new Bundle();
        ArrayList<MediaWrapper> list = mMediaLists != null ? mMediaLists.get(position) : null;
        if (list != null && !list.isEmpty())
            args.putParcelableArrayList(KEY_MEDIA_LIST, list);
        args.putParcelable(KEY_MEDIA, media);
        next.setArguments(args);
        ft.replace(R.id.fragment_placeholder, next, media.getLocation());
        ft.addToBackStack(mMrl);
        ft.commit();
    }

    @Override
    public void onMediaAdded(int index, Media media) {
        mAdapter.addItem(media, mReadyToDisplay && mRoot, mRoot);
        if (mReadyToDisplay)
            updateEmptyView();
        if (mRoot)
            mHandler.sendEmptyMessage(BrowserFragmentHandler.MSG_HIDE_LOADING);
    }

    @Override
    public void onMediaRemoved(int index, Media media) {
        mAdapter.removeItem(index, mReadyToDisplay);
    }

    @Override
    public void onBrowseEnd() {
        releaseBrowser();
        mHandler.sendEmptyMessage(BrowserFragmentHandler.MSG_HIDE_LOADING);
        if (mReadyToDisplay)
            display();
    }

    @Override
    public void onRefresh() {
        mSavedPosition = mLayoutManager.findFirstCompletelyVisibleItemPosition();
        refresh();
    }

    RecyclerView.OnScrollListener mScrollListener = new RecyclerView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);
        }

        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            int topRowVerticalPosition = (recyclerView == null || recyclerView.getChildCount() == 0) ? 0
                    : recyclerView.getChildAt(0).getTop();
            mSwipeRefreshLayout.setEnabled(topRowVerticalPosition >= 0);
        }
    };

    /**
     * Update views visibility and emptiness info
     */
    protected void updateEmptyView() {
        if (mAdapter.isEmpty()) {
            mEmptyView.setText(getString(R.string.directory_empty));
            mEmptyView.setVisibility(View.VISIBLE);
            mRecyclerView.setVisibility(View.GONE);
            mSwipeRefreshLayout.setEnabled(false);
        } else if (mEmptyView.getVisibility() == View.VISIBLE) {
            mEmptyView.setVisibility(View.GONE);
            mRecyclerView.setVisibility(View.VISIBLE);
            mSwipeRefreshLayout.setEnabled(true);
        }
    }

    protected void update() {
        update(false);
    }

    protected void update(boolean force) {
        if (mReadyToDisplay) {
            updateEmptyView();
            if (force || mAdapter.isEmpty()) {
                refresh();
            } else {
                updateDisplay();
            }
        }
    }

    protected void updateDisplay() {
        if (!mAdapter.isEmpty()) {
            if (mSavedPosition > 0) {
                mLayoutManager.scrollToPositionWithOffset(mSavedPosition, 0);
                mSavedPosition = 0;
            }
        }
        mAdapter.notifyDataSetChanged();
        parseSubDirectories();
        focusHelper();
    }

    @Override
    public void refresh() {
        mAdapter.clear();
        if (mMediaBrowser == null)
            mMediaBrowser = new MediaBrowser(VLCInstance.get(), this);
        else
            mMediaBrowser.changeEventListener(this);
        mCurrentParsedPosition = 0;
        if (mRoot)
            browseRoot();
        else
            mMediaBrowser.browse(mCurrentMedia != null ? mCurrentMedia.getUri() : Uri.parse(mMrl));
        mHandler.sendEmptyMessageDelayed(BrowserFragmentHandler.MSG_SHOW_LOADING, 300);
    }

    protected static class BrowserFragmentHandler extends WeakHandler<BaseBrowserFragment> {

        public static final int MSG_SHOW_LOADING = 0;
        public static final int MSG_HIDE_LOADING = 1;

        public BrowserFragmentHandler(BaseBrowserFragment owner) {
            super(owner);
        }

        @Override
        public void handleMessage(Message msg) {
            BaseBrowserFragment fragment = getOwner();
            switch (msg.what) {
            case MSG_SHOW_LOADING:
                fragment.mSwipeRefreshLayout.setRefreshing(true);
                break;
            case MSG_HIDE_LOADING:
                removeMessages(MSG_SHOW_LOADING);
                fragment.mSwipeRefreshLayout.setRefreshing(false);
                break;
            }
        }
    }

    protected void focusHelper() {
        if (getActivity() == null)
            return;
        boolean isEmpty = mAdapter.isEmpty();
        MainActivity main = (MainActivity) getActivity();
        main.setMenuFocusDown(isEmpty, R.id.network_list);
        main.setSearchAsFocusDown(isEmpty, getView(), R.id.network_list);
    }

    public void clear() {
        mAdapter.clear();
    }

    @Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
        ContextMenuRecyclerView.RecyclerContextMenuInfo info = (ContextMenuRecyclerView.RecyclerContextMenuInfo) menuInfo;
        if (info != null)
            setContextMenu(getActivity().getMenuInflater(), menu, info.position);
    }

    protected void setContextMenu(MenuInflater inflater, Menu menu, int position) {
        MediaWrapper mw = (MediaWrapper) mAdapter.getItem(position);
        boolean canWrite = Util.canWrite(mw.getLocation());
        boolean isAudio = mw.getType() == MediaWrapper.TYPE_AUDIO;
        boolean isVideo = mw.getType() == MediaWrapper.TYPE_VIDEO;
        if (isAudio || isVideo) {
            inflater.inflate(R.menu.directory_view_file, menu);
            menu.findItem(R.id.directory_view_delete).setVisible(canWrite);
            menu.findItem(R.id.directory_view_info).setVisible(isVideo);
        } else if (mw.getType() == MediaWrapper.TYPE_DIR) {
            boolean isEmpty = mMediaLists.get(position) == null || mMediaLists.get(position).isEmpty();
            if (canWrite || !isEmpty) {
                inflater.inflate(R.menu.directory_view_dir, menu);
                //                if (canWrite) {
                //                    boolean nomedia = new File(mw.getLocation() + "/.nomedia").exists();
                //                    menu.findItem(R.id.directory_view_hide_media).setVisible(!nomedia);
                //                    menu.findItem(R.id.directory_view_show_media).setVisible(nomedia);
                //                } else {
                //                    menu.findItem(R.id.directory_view_hide_media).setVisible(false);
                //                    menu.findItem(R.id.directory_view_show_media).setVisible(false);
                //                }
                menu.findItem(R.id.directory_view_play_folder).setVisible(!isEmpty);
                menu.findItem(R.id.directory_view_delete).setVisible(canWrite);
            }
        }
    }

    @Override
    public boolean onContextItemSelected(MenuItem item) {
        ContextMenuRecyclerView.RecyclerContextMenuInfo info = (ContextMenuRecyclerView.RecyclerContextMenuInfo) item
                .getMenuInfo();
        if (info != null && handleContextItemSelected(item, info.position))
            return true;
        return super.onContextItemSelected(item);
    }

    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    public void onPopupMenu(View anchor, final int position) {
        if (!AndroidUtil.isHoneycombOrLater()) {
            // Call the "classic" context menu
            anchor.performLongClick();
            return;
        }
        PopupMenu popupMenu = new PopupMenu(getActivity(), anchor);
        setContextMenu(popupMenu.getMenuInflater(), popupMenu.getMenu(), position);

        popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem item) {
                return handleContextItemSelected(item, position);
            }
        });
        popupMenu.show();
    }

    protected boolean handleContextItemSelected(MenuItem item, int position) {
        int id = item.getItemId();
        if (!(mAdapter.getItem(position) instanceof MediaWrapper))
            return super.onContextItemSelected(item);
        MediaWrapper mw = (MediaWrapper) mAdapter.getItem(position);
        switch (id) {
        case R.id.directory_view_play:
            Util.openMedia(getActivity(), (MediaWrapper) mAdapter.getItem(position));
            return true;
        case R.id.directory_view_append: {
            PlaybackServiceClient.append(getActivity(), null, mw);
            return true;
        }
        case R.id.directory_view_delete:
            AlertDialog alertDialog = CommonDialogs.deleteMedia(mw.getType(), getActivity(), mw.getLocation(),
                    new VLCRunnable() {
                        @Override
                        public void run(Object o) {
                            refresh();
                        }
                    });
            alertDialog.show();
            return true;
        case R.id.directory_view_info:
            Intent i = new Intent(getActivity(), SecondaryActivity.class);
            i.putExtra("fragment", "mediaInfo");
            i.putExtra("param", mw.getUri().toString());
            startActivity(i);
            return true;
        case R.id.directory_view_play_audio: {
            PlaybackServiceClient.load(getActivity(), null, mw);
            return true;
        }
        case R.id.directory_view_play_video:
            VideoPlayerActivity.start(getActivity(), mw.getUri());
            return true;
        case R.id.directory_view_play_folder:
            ArrayList<MediaWrapper> mediaList = new ArrayList<MediaWrapper>();
            for (MediaWrapper mediaItem : mMediaLists.get(position)) {
                if (mediaItem.getType() == MediaWrapper.TYPE_AUDIO
                        || mediaItem.getType() == MediaWrapper.TYPE_VIDEO)
                    mediaList.add(mediaItem);
            }
            Util.openList(getActivity(), mediaList, 0);
            return true;
        //            case R.id.directory_view_hide_media:
        //                try {
        //                    if (new File(mw.getLocation()+"/.nomedia").createNewFile())
        //                        updateLib();
        //                } catch (IOException e) {}
        //                return true;
        //            case R.id.directory_view_show_media:
        //                if (new File(mw.getLocation()+"/.nomedia").delete())
        //                    updateLib();
        //                return true;
        }
        return false;
    }

    protected void parseSubDirectories() {
        if (mCurrentParsedPosition == -1 || mAdapter.isEmpty())
            return;
        mMediaLists.clear();
        if (mMediaBrowser == null)
            mMediaBrowser = new MediaBrowser(VLCInstance.get(), mFoldersBrowserListener);
        else
            mMediaBrowser.changeEventListener(mFoldersBrowserListener);
        mCurrentParsedPosition = 0;
        Object item;
        MediaWrapper mw;
        while (mCurrentParsedPosition < mAdapter.getItemCount()) {
            item = mAdapter.getItem(mCurrentParsedPosition);
            if (item instanceof BaseBrowserAdapter.Storage) {
                mw = new MediaWrapper(((BaseBrowserAdapter.Storage) item).getUri());
                mw.setType(MediaWrapper.TYPE_DIR);
            } else if (item instanceof MediaWrapper) {
                mw = (MediaWrapper) item;
            } else
                mw = null;
            if (mw != null) {
                if (mw.getType() == MediaWrapper.TYPE_DIR || mw.getType() == MediaWrapper.TYPE_PLAYLIST) {
                    mMediaBrowser.browse(mw.getUri());
                    return;
                }
            }
            ++mCurrentParsedPosition;
        }
    }

    private MediaBrowser.EventListener mFoldersBrowserListener = new MediaBrowser.EventListener() {
        ArrayList<MediaWrapper> directories = new ArrayList<MediaWrapper>();
        ArrayList<MediaWrapper> files = new ArrayList<MediaWrapper>();

        @Override
        public void onMediaAdded(int index, Media media) {
            int type = media.getType();
            if (type == Media.Type.Directory)
                directories.add(new MediaWrapper(media));
            else if (type == Media.Type.File)
                files.add(new MediaWrapper(media));
        }

        @Override
        public void onMediaRemoved(int index, Media media) {
        }

        @Override
        public void onBrowseEnd() {
            if (mAdapter.isEmpty()) {
                mCurrentParsedPosition = -1;
                releaseBrowser();
                return;
            }
            String holderText = getDescription(directories.size(), files.size());
            MediaWrapper mw = null;

            if (!TextUtils.equals(holderText, "")) {
                mAdapter.setDescription(mCurrentParsedPosition, holderText);
                directories.addAll(files);
                mMediaLists.put(mCurrentParsedPosition, new ArrayList<MediaWrapper>(directories));
            }
            while (++mCurrentParsedPosition < mAdapter.getItemCount()) { //skip media that are not browsable
                if (mAdapter.getItem(mCurrentParsedPosition) instanceof MediaWrapper) {
                    mw = (MediaWrapper) mAdapter.getItem(mCurrentParsedPosition);
                    if (mw.getType() == MediaWrapper.TYPE_DIR || mw.getType() == MediaWrapper.TYPE_PLAYLIST)
                        break;
                } else if (mAdapter.getItem(mCurrentParsedPosition) instanceof BaseBrowserAdapter.Storage) {
                    mw = new MediaWrapper(
                            ((BaseBrowserAdapter.Storage) mAdapter.getItem(mCurrentParsedPosition)).getUri());
                    break;
                } else
                    mw = null;
            }

            if (mw != null) {
                if (mCurrentParsedPosition < mAdapter.getItemCount()) {
                    mMediaBrowser.browse(mw.getUri());
                } else {
                    mCurrentParsedPosition = -1;
                    releaseBrowser();
                }
            } else
                releaseBrowser();
            directories.clear();
            files.clear();
        }

        private String getDescription(int folderCount, int mediaFileCount) {
            String holderText = "";
            if (folderCount > 0) {
                holderText += VLCApplication.getAppResources().getQuantityString(R.plurals.subfolders_quantity,
                        folderCount, folderCount);
                if (mediaFileCount > 0)
                    holderText += ", ";
            }
            if (mediaFileCount > 0)
                holderText += VLCApplication.getAppResources().getQuantityString(R.plurals.mediafiles_quantity,
                        mediaFileCount, mediaFileCount);
            else if (folderCount == 0 && mediaFileCount == 0)
                holderText = getString(R.string.directory_empty);
            return holderText;
        }
    };
}