net.mm2d.dmsexplorer.CdsListActivity.java Source code

Java tutorial

Introduction

Here is the source code for net.mm2d.dmsexplorer.CdsListActivity.java

Source

/*
 * Copyright (c) 2016 ? (OHMAE Ryosuke)
 *
 * This software is released under the MIT License.
 * http://opensource.org/licenses/MIT
 */

package net.mm2d.dmsexplorer;

import android.app.ActivityOptions;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.os.Handler;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.NonNull;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.transition.Fade;
import android.transition.Slide;
import android.transition.TransitionSet;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;

import net.mm2d.android.cds.BrowseResult;
import net.mm2d.android.cds.CdsObject;
import net.mm2d.android.cds.MediaServer;
import net.mm2d.android.widget.DividerItemDecoration;

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ExecutionException;

/**
 * MediaServer?ContentDirectory???Activity
 *
 * @author <a href="mailto:ryo@mm2d.net">?(OHMAE Ryosuke)</a>
 */
public class CdsListActivity extends AppCompatActivity implements BrowseResult.StatusListener {
    private static final String TAG = "CdsListActivity";
    private static final String KEY_HISTORY = "KEY_HISTORY";
    private static final String KEY_SELECTED = "KEY_SELECTED";
    private static final String KEY_POSITION = "KEY_POSITION";
    private boolean mTwoPane;
    private final DataHolder mDataHolder = DataHolder.getInstance();
    private Handler mHandler;
    private MediaServer mServer;
    private BrowseResult mBrowseResult;
    private final LinkedList<History> mHistories = new LinkedList<>();
    private String mSubtitle;
    private CdsObject mSelectedObject;
    private CdsDetailFragment mCdsDetailFragment;
    private SwipeRefreshLayout mSwipeRefreshLayout;
    private RecyclerView mRecyclerView;
    private CdsListAdapter mCdsListAdapter;

    /**
     * ??
     *
     * <p>Bundle????????????
     *
     * @param context 
     * @param udn     MediaServer?UDN
     * @return 
     */
    @NonNull
    public static Intent makeIntent(@NonNull Context context, @NonNull String udn) {
        final Intent intent = new Intent(context, CdsListActivity.class);
        intent.putExtra(Const.EXTRA_UDN, udn);
        return intent;
    }

    private static class History implements Parcelable {
        private final int mPosition;
        private final String mId;
        private final String mTitle;

        public History(int position, @NonNull String id, @NonNull String title) {
            mPosition = position;
            mId = id;
            mTitle = title;
        }

        public int getPosition() {
            return mPosition;
        }

        public String getId() {
            return mId;
        }

        public String getTitle() {
            return mTitle;
        }

        private History(Parcel in) {
            mPosition = in.readInt();
            mId = in.readString();
            mTitle = in.readString();
        }

        @Override
        public int describeContents() {
            return 0;
        }

        @Override
        public void writeToParcel(Parcel dest, int flags) {
            dest.writeInt(mPosition);
            dest.writeString(mId);
            dest.writeString(mTitle);
        }

        public static final Creator<History> CREATOR = new Creator<History>() {
            @Override
            public History createFromParcel(Parcel in) {
                return new History(in);
            }

            @Override
            public History[] newArray(int size) {
                return new History[size];
            }
        };
    }

    private void onCdsItemClick(final View v, final View accent, int position, CdsObject object) {
        if (object.isContainer()) {
            browse(position, object.getObjectId(), object.getTitle(), true);
            return;
        }
        if (mTwoPane) {
            if (mSelectedObject != null && mSelectedObject.equals(object)) {
                return;
            }
            mCdsDetailFragment = CdsDetailFragment.newInstance(mServer.getUdn(), object);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                mCdsDetailFragment.setEnterTransition(new Slide(Gravity.START));
            }
            getSupportFragmentManager().beginTransaction().replace(R.id.cds_detail_container, mCdsDetailFragment)
                    .commit();
        } else {
            final Intent intent = CdsDetailActivity.makeIntent(v.getContext(), mServer.getUdn(), object);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                startActivity(intent, ActivityOptions
                        .makeSceneTransitionAnimation(CdsListActivity.this, accent, "share").toBundle());
            } else {
                startActivity(intent);
            }
        }
        mSelectedObject = object;
        mCdsListAdapter.setSelection(position);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
            final TransitionSet ts = new TransitionSet();
            ts.addTransition(new Slide(Gravity.END));
            ts.addTransition(new Fade());
            getWindow().setEnterTransition(ts);
        }
        mHandler = new Handler();
        final String udn = getIntent().getStringExtra(Const.EXTRA_UDN);
        mServer = mDataHolder.getMsControlPoint().getMediaServer(udn);
        if (mServer == null) {
            finish();
            return;
        }
        final String name = mServer.getFriendlyName();
        if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
            getWindow().setStatusBarColor(ThemeUtils.getAccentDarkColor(name));
        }
        setContentView(R.layout.act_cds_list);
        final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        toolbar.setBackgroundColor(ThemeUtils.getAccentColor(name));
        final ActionBar actionBar = getSupportActionBar();
        actionBar.setDisplayHomeAsUpEnabled(true);
        actionBar.setTitle(name);

        mSwipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipeRefresh);
        mSwipeRefreshLayout.setColorSchemeResources(R.color.progress1, R.color.progress2, R.color.progress3,
                R.color.progress4);
        mSwipeRefreshLayout.setOnRefreshListener(() -> {
            mDataHolder.popCache();
            reload();
        });
        mCdsListAdapter = new CdsListAdapter(this);
        mCdsListAdapter.setOnItemClickListener(this::onCdsItemClick);
        mRecyclerView = (RecyclerView) findViewById(R.id.cds_list);
        mRecyclerView.setAdapter(mCdsListAdapter);
        mRecyclerView.addItemDecoration(new DividerItemDecoration(this));

        if (findViewById(R.id.cds_detail_container) != null) {
            mTwoPane = true;
        }
        if (savedInstanceState == null) {
            browse(0, "0", "", true);
        }
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        final History[] histories = (History[]) savedInstanceState.getParcelableArray(KEY_HISTORY);
        Collections.addAll(mHistories, histories);
        final History history = mHistories.peekLast();
        if (history.getId().equals(mDataHolder.getCurrentContainer())) {
            prepareViewState();
            updateListView(mDataHolder.getCurrentList(), true);
        } else {
            browse(history.getPosition(), history.getId(), history.getTitle(), false);
        }
        mSelectedObject = savedInstanceState.getParcelable(KEY_SELECTED);
        final int position = savedInstanceState.getInt(KEY_POSITION, -1);
        mCdsListAdapter.setSelection(position);
        if (position >= 0) {
            mRecyclerView.scrollToPosition(position);
        }
        if (mTwoPane && mSelectedObject != null) {
            final Bundle arguments = new Bundle();
            arguments.putString(Const.EXTRA_UDN, mServer.getUdn());
            arguments.putParcelable(Const.EXTRA_OBJECT, mSelectedObject);
            mCdsDetailFragment = new CdsDetailFragment();
            mCdsDetailFragment.setArguments(arguments);
            getSupportFragmentManager().beginTransaction().replace(R.id.cds_detail_container, mCdsDetailFragment)
                    .commit();
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putParcelableArray(KEY_HISTORY, mHistories.toArray(new History[mHistories.size()]));
        outState.putInt(KEY_POSITION, mCdsListAdapter.getSelection());
        if (mSelectedObject != null) {
            outState.putParcelable(KEY_SELECTED, mSelectedObject);
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mBrowseResult != null) {
            mBrowseResult.cancel(true);
        }
        if (isFinishing()) {
            mDataHolder.clearCache();
        }
    }

    @Override
    public void onBackPressed() {
        if (mHistories.size() <= 1) {
            super.onBackPressed();
        } else {
            if (mBrowseResult != null) {
                mBrowseResult.cancel(true);
            }
            mHandler.removeCallbacks(mUpdateListView);
            final History history = mHistories.removeLast();
            final int position = history.getPosition();
            if (!mDataHolder.getCurrentContainer().equals(mHistories.peekLast().getId())) {
                mDataHolder.popCache();
            }
            prepareViewState();
            updateListView(mDataHolder.getCurrentList(), true);
            mCdsListAdapter.setSelection(position);
            final LinearLayoutManager llm = (LinearLayoutManager) mRecyclerView.getLayoutManager();
            llm.scrollToPositionWithOffset(position, mRecyclerView.getHeight() / 3);
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        final int id = item.getItemId();
        switch (id) {
        case R.id.action_settings:
            startActivity(SettingsActivity.makeIntent(this));
            return true;
        case android.R.id.home:
            onBackPressed();
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    private void browse(int position, String objectId, String title, boolean push) {
        if (mBrowseResult != null) {
            mBrowseResult.cancel(true);
        }
        if (push) {
            mHistories.addLast(new History(position, objectId, title));
        }
        prepareViewState();
        reload();
    }

    private void prepareViewState() {
        if (mTwoPane && mCdsDetailFragment != null) {
            getSupportFragmentManager().beginTransaction().remove(mCdsDetailFragment).commit();
        }
        mCdsListAdapter.setSelection(-1);
        mCdsDetailFragment = null;
        mSelectedObject = null;
        final StringBuilder sb = new StringBuilder();
        for (final History history : mHistories) {
            if (sb.length() != 0) {
                sb.append(" > ");
            }
            sb.append(history.getTitle());
        }
        mSubtitle = sb.toString();
        final ActionBar actionBar = getSupportActionBar();
        actionBar.setSubtitle(mSubtitle);
    }

    private void reload() {
        mSwipeRefreshLayout.setRefreshing(true);
        mCdsListAdapter.clear();
        mCdsListAdapter.notifyDataSetChanged();
        final History history = mHistories.peekLast();
        mBrowseResult = mServer.browse(history.getId());
        mBrowseResult.setStatusListener(this);
    }

    @Override
    public void onCompletion(@NonNull BrowseResult result) {
        if (mBrowseResult.isCancelled()) {
            return;
        }
        final History history = mHistories.peekLast();
        try {
            final List<CdsObject> list = result.get();
            mDataHolder.pushCache(history.getId(), list);
            updateListViewAsync(list, true);
        } catch (InterruptedException | ExecutionException ignored) {
            // ????Exception???????
        }
    }

    @Override
    public void onProgressUpdate(@NonNull BrowseResult result) {
        updateListViewAsync(result.getProgress(), false);
    }

    private void updateListViewAsync(final List<CdsObject> result, final boolean completion) {
        mHandler.removeCallbacks(mUpdateListView);
        mUpdateListView.set(result, completion);
        mHandler.post(mUpdateListView);
    }

    private final UpdateListView mUpdateListView = new UpdateListView();

    private class UpdateListView implements Runnable {
        private List<CdsObject> mResult;
        private boolean mCompletion;

        public void set(List<CdsObject> result, boolean completion) {
            mResult = result;
            mCompletion = completion;
        }

        @Override
        public void run() {
            updateListView(mResult, mCompletion);
        }
    }

    private void updateListView(List<CdsObject> result, boolean completion) {
        final int beforeCount = mCdsListAdapter.getItemCount();
        mCdsListAdapter.clear();
        if (result != null) {
            mCdsListAdapter.addAll(result);
        }
        if (completion) {
            mSwipeRefreshLayout.setRefreshing(false);
        }
        final int count = mCdsListAdapter.getItemCount();
        final ActionBar actionBar = getSupportActionBar();
        assert actionBar != null;
        actionBar.setSubtitle(mSubtitle + "  [" + count + "]");
        mCdsListAdapter.notifyItemRangeInserted(beforeCount, count - beforeCount);
    }
}