Android Open Source - DroidUPnP Content Directory Fragment






From Project

Back to project page DroidUPnP.

License

The source code is released under:

GNU General Public License

If you think the Android project DroidUPnP listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/**
 * Copyright (C) 2013 Aurlien Chabot <aurelien@chabot.fr>
 */*  w w  w .j  a v  a 2 s  .c  o  m*/
 * This file is part of DroidUPNP.
 *
 * DroidUPNP 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 3 of the License, or
 * (at your option) any later version.
 *
 * DroidUPNP 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 DroidUPNP.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.droidupnp.view;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedList;
import java.util.Observable;
import java.util.Observer;
import java.util.concurrent.Callable;

import org.droidupnp.Main;
import org.droidupnp.R;
import org.droidupnp.model.upnp.IDeviceDiscoveryObserver;
import org.droidupnp.model.upnp.didl.DIDLDevice;
import org.droidupnp.model.upnp.CallableContentDirectoryFilter;
import org.droidupnp.model.upnp.IContentDirectoryCommand;
import org.droidupnp.model.upnp.IRendererCommand;
import org.droidupnp.model.upnp.IUpnpDevice;
import org.droidupnp.model.upnp.didl.IDIDLContainer;
import org.droidupnp.model.upnp.didl.IDIDLItem;
import org.droidupnp.model.upnp.didl.IDIDLObject;
import org.droidupnp.model.upnp.didl.IDIDLParentContainer;

import android.app.Activity;
import android.app.ListFragment;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

import uk.co.senab.actionbarpulltorefresh.library.ActionBarPullToRefresh;
import uk.co.senab.actionbarpulltorefresh.library.PullToRefreshLayout;

public class ContentDirectoryFragment extends ListFragment implements Observer
{
  private static final String TAG = "ContentDirectoryFragment";

  private ArrayAdapter<DIDLObjectDisplay> contentList;
  private LinkedList<String> tree = null;
  private String currentID = null;
  private IUpnpDevice device;

  private IContentDirectoryCommand contentDirectoryCommand;

  static final String STATE_CONTENTDIRECTORY = "contentDirectory";
  static final String STATE_TREE = "tree";
  static final String STATE_CURRENT = "current";

  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
  {
    // Inflate the layout for this fragment
    return inflater.inflate(R.layout.browsing_list_fragment, container, false);
  }

  /** This update the search visibility depending on current content directory capabilities */
  public void updateSearchVisibility()
  {
    final Activity a = getActivity();
    if(a!=null) {
      a.runOnUiThread(new Runnable() {
        @Override
        public void run() {
          try {
            Main.setSearchVisibility(contentDirectoryCommand!=null && contentDirectoryCommand.isSearchAvailable());
          } catch (Exception e) {
            e.printStackTrace();
          }
        }
      });
    }
  }

  private DeviceObserver deviceObserver;

  public class DeviceObserver implements IDeviceDiscoveryObserver
  {
    ContentDirectoryFragment cdf;

    public DeviceObserver(ContentDirectoryFragment cdf){
      this.cdf = cdf;
    }

    @Override
    public void addedDevice(IUpnpDevice device) {
      if(Main.upnpServiceController.getSelectedContentDirectory() == null)
        cdf.update();
    }

    @Override
    public void removedDevice(IUpnpDevice device) {
      if(Main.upnpServiceController.getSelectedContentDirectory() == null)
        cdf.update();
    }
  }

  public class CustomAdapter extends ArrayAdapter<DIDLObjectDisplay>
  {
    private final int layout;
    private LayoutInflater inflater;

    public CustomAdapter(Context context) {
      super(context, 0);
      this.inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
      this.layout = R.layout.browsing_list_item;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent)
    {
      if (convertView == null)
        convertView = inflater.inflate(layout, null);

      // Item
      final DIDLObjectDisplay entry = getItem(position);

      ImageView imageView = (ImageView) convertView.findViewById(R.id.icon);
      imageView.setImageResource(entry.getIcon());

      TextView text1 = (TextView) convertView.findViewById(R.id.text1);
      text1.setText(entry.getTitle());

      TextView text2 = (TextView) convertView.findViewById(R.id.text2);
      text2.setText((entry.getDescription()!=null) ? entry.getDescription() : "");

      TextView text3 = (TextView) convertView.findViewById(R.id.text3);
      text3.setText(entry.getCount());

      return convertView;
    }
  }

  @Override
  public void onActivityCreated(Bundle savedInstanceState)
  {
    super.onActivityCreated(savedInstanceState);

    contentList = new CustomAdapter(this.getView().getContext());

    setListAdapter(contentList);

    deviceObserver = new DeviceObserver(this);
    Main.upnpServiceController.getContentDirectoryDiscovery().addObserver(deviceObserver);

    // Listen to content directory change
    if (Main.upnpServiceController != null)
      Main.upnpServiceController.addSelectedContentDirectoryObserver(this);
    else
      Log.w(TAG, "upnpServiceController was not ready !!!");

    if (savedInstanceState != null
      && savedInstanceState.getStringArray(STATE_TREE) != null
      && Main.upnpServiceController.getSelectedContentDirectory() != null
      && 0 == Main.upnpServiceController.getSelectedContentDirectory().getUID()
      .compareTo(savedInstanceState.getString(STATE_CONTENTDIRECTORY)))
    {
      Log.i(TAG, "Restore previews state");

      // Content directory is still the same => reload context
      tree = new LinkedList<>(Arrays.asList(savedInstanceState.getStringArray(STATE_TREE)));
      currentID = savedInstanceState.getString(STATE_CURRENT);

      device = Main.upnpServiceController.getSelectedContentDirectory();
      contentDirectoryCommand = Main.factory.createContentDirectoryCommand();
    }

    Log.d(TAG, "Force refresh");
    refresh();
  }

  @Override
  public void onDestroy()
  {
    super.onDestroy();
    Main.upnpServiceController.delSelectedContentDirectoryObserver(this);
    Main.upnpServiceController.getContentDirectoryDiscovery().removeObserver(deviceObserver);
  }

  private PullToRefreshLayout mPullToRefreshLayout;

  @Override
  public void onViewCreated(View view, Bundle savedInstanceState)
  {
    super.onViewCreated(view, savedInstanceState);

    // This is the View which is created by ListFragment
    ViewGroup viewGroup = (ViewGroup) view;

    view.setBackgroundColor(getResources().getColor(R.color.grey));

    // We need to create a PullToRefreshLayout manually
    mPullToRefreshLayout = new PullToRefreshLayout(viewGroup.getContext());

    // We can now setup the PullToRefreshLayout
    ActionBarPullToRefresh.from(getActivity())
      .insertLayoutInto(viewGroup)
      .theseChildrenArePullable(getListView(), getListView().getEmptyView())
      .listener(new uk.co.senab.actionbarpulltorefresh.library.listeners.OnRefreshListener() {
        @Override
        public void onRefreshStarted(View view) {
          refresh();
        }
      })
      .setup(mPullToRefreshLayout);
  }

  @Override
  public void onDestroyView()
  {
    mPullToRefreshLayout.setRefreshComplete();
    super.onDestroyView();
  }

  @Override
  public void onSaveInstanceState(Bundle savedInstanceState)
  {
    Log.i(TAG, "Save instance state");

    if (Main.upnpServiceController.getSelectedContentDirectory() == null)
      return;

    savedInstanceState.putString(STATE_CONTENTDIRECTORY, Main.upnpServiceController.getSelectedContentDirectory()
      .getUID());

    if (tree != null)
    {
      String[] arrayTree = new String[tree.size()];
      int i = 0;
      for (String s : tree)
        arrayTree[i++] = s;

      savedInstanceState.putStringArray(STATE_TREE, arrayTree);
      savedInstanceState.putString(STATE_CURRENT, currentID);
    }

    super.onSaveInstanceState(savedInstanceState);
  }

  @Override
  public void onResume()
  {
    super.onResume();
    contentList.clear();
    refresh();
  }

  public Boolean goBack()
  {
    if(tree == null || tree.isEmpty())
    {
      if(Main.upnpServiceController.getSelectedContentDirectory() != null)
      {
        // Back on device root, unselect device
        Main.upnpServiceController.setSelectedContentDirectory(null);
        return false;
      }
      else
      {
        // Already at the upper level
        return true;
      }
    }
    else
    {
      // Go back in browsing
      currentID = tree.pop();
      update();
      return false;
    }
  }

  public void printCurrentContentDirectoryInfo()
  {
    Log.i(TAG, "Device : " + Main.upnpServiceController.getSelectedContentDirectory().getDisplayString());
    Main.upnpServiceController.getSelectedContentDirectory().printService();
  }

  public class RefreshCallback implements Callable<Void> {
    public Void call() throws java.lang.Exception {
      final Activity a = getActivity();
      if(a!=null) {
        a.runOnUiThread(new Runnable() {
          @Override
          public void run() {
            try {
              setListShown(true);
              mPullToRefreshLayout.setRefreshComplete();
            } catch (Exception e) {
              e.printStackTrace();
            }
          }
        });
      }
      return null;
    }
  }

  public class ContentCallback extends RefreshCallback
  {
    private ArrayAdapter<DIDLObjectDisplay> contentList;
    private ArrayList<DIDLObjectDisplay> content;

    public ContentCallback(ArrayAdapter<DIDLObjectDisplay> contentList)
    {
      this.contentList = contentList;
      this.content = new ArrayList<>();
    }

    public void setContent(ArrayList<DIDLObjectDisplay> content)
    {
      this.content = content;
    }

    public Void call() throws java.lang.Exception
    {
      final Activity a = getActivity();
      if(a!=null) {
        a.runOnUiThread(new Runnable() {
          @Override
          public void run() {
            try {
              // Empty the list
              contentList.clear();
              // Fill the list
              contentList.addAll(content);
            } catch (Exception e) {
              e.printStackTrace();
            }
          }
        });
      }
      // Refresh
      return super.call();
    }
  }

  public synchronized void refresh()
  {
    Log.d(TAG, "refresh");

    final Activity a = getActivity();
    if(a!=null) {
      a.runOnUiThread(new Runnable() {
        @Override
        public void run() {
          try {
            setListShown(false);
            mPullToRefreshLayout.setRefreshComplete();
            mPullToRefreshLayout.setRefreshing(true);
          } catch (Exception e) {
            e.printStackTrace();
          }
        }
      });
    }

    // Update search visibility
    updateSearchVisibility();

    if (Main.upnpServiceController.getSelectedContentDirectory() == null)
    {
      if (device != null)
      {
        Log.i(TAG, "Current content directory have been removed");
        device = null;
        tree = null;
      }

      // Fill with the content directory list
      final Collection<IUpnpDevice> upnpDevices = Main.upnpServiceController.getServiceListener()
        .getFilteredDeviceList(new CallableContentDirectoryFilter());

      ArrayList<DIDLObjectDisplay> list = new ArrayList<DIDLObjectDisplay>();
      for (IUpnpDevice upnpDevice : upnpDevices)
        list.add(new DIDLObjectDisplay(new DIDLDevice(upnpDevice)));

      try {
        ContentCallback cc = new ContentCallback(contentList);
        cc.setContent(list);
        cc.call();
      } catch (Exception e){e.printStackTrace();}

      return;
    }

    Log.i(TAG, "device " + device + " device " + ((device != null) ? device.getDisplayString() : ""));
    Log.i(TAG, "contentDirectoryCommand : " + contentDirectoryCommand);

    contentDirectoryCommand = Main.factory.createContentDirectoryCommand();
    if (contentDirectoryCommand == null)
      return; // Can't do anything if upnp not ready

    if (device == null || !device.equals(Main.upnpServiceController.getSelectedContentDirectory()))
    {
      device = Main.upnpServiceController.getSelectedContentDirectory();

      Log.i(TAG, "Content directory changed !!! "
        + Main.upnpServiceController.getSelectedContentDirectory().getDisplayString());

      tree = new LinkedList<String>();

      Log.i(TAG, "Browse root of a new device");
      contentDirectoryCommand.browse("0", null, new ContentCallback(contentList));
    }
    else
    {
      if (tree != null && tree.size() > 0)
      {
        String parentID = (tree.size() > 0) ? tree.getLast() : null;
        Log.i(TAG, "Browse, currentID : " + currentID + ", parentID : " + parentID);
        contentDirectoryCommand.browse(currentID, parentID, new ContentCallback(contentList));
      }
      else
      {
        Log.i(TAG, "Browse root");
        contentDirectoryCommand.browse("0", null, new ContentCallback(contentList));
      }
    }
  }

  @Override
  public void onListItemClick(ListView l, View v, int position, long id)
  {
    super.onListItemClick(l, v, position, id);

    IDIDLObject didl = contentList.getItem(position).getDIDLObject();

    try {
      if(didl instanceof DIDLDevice)
      {
        Main.upnpServiceController.setSelectedContentDirectory( ((DIDLDevice)didl).getDevice(), false );

        // Refresh display
        refresh();
      }
      else if (didl instanceof IDIDLContainer)
      {
        // Update position
        if (didl instanceof IDIDLParentContainer)
        {
          currentID = tree.pop();
        }
        else
        {
          currentID = didl.getId();
          String parentID = didl.getParentID();
          tree.push(parentID);
        }

        // Refresh display
        refresh();
      }
      else if (didl instanceof IDIDLItem)
      {
        // Launch item
        launchURI((IDIDLItem) didl);
      }
    } catch (Exception e) {
      Log.e(TAG, "Unable to finish action after item click");
      e.printStackTrace();
    }
  }

  private void launchURI(final IDIDLItem uri)
  {
    if (Main.upnpServiceController.getSelectedRenderer() == null)
    {
      // No renderer selected yet, open a popup to select one
      final Activity a = getActivity();
      if(a!=null) {
        a.runOnUiThread(new Runnable(){
          @Override
          public void run() {
            try {
              RendererDialog rendererDialog = new RendererDialog();
              rendererDialog.setCallback(new Callable<Void>() {
                @Override
                public Void call() throws Exception {
                  launchURIRenderer(uri);
                  return null;
                }
              });
              rendererDialog.show(getActivity().getFragmentManager(), "RendererDialog");
            } catch (Exception e) {
              e.printStackTrace();
            }
          }
        });
      }
    }
    else
    {
      // Renderer available, go for it
      launchURIRenderer(uri);
    }

  }

  private void launchURIRenderer(IDIDLItem uri)
  {
    IRendererCommand rendererCommand = Main.factory.createRendererCommand(Main.factory.createRendererState());
    rendererCommand.launchItem(uri);
  }

  @Override
  public void update(Observable observable, Object data)
  {
    Log.i(TAG, "ContentDirectory have changed");
    update();
  }

  public void update()
  {
    final Activity a = getActivity();
    if(a!=null) {
      a.runOnUiThread(new Runnable() {
        @Override
        public void run() {
          refresh();
        }
      });
    }
  }
}




Java Source Code List

fi.iki.elonen.NanoHTTPD.java
fi.iki.elonen.ServerRunner.java
fi.iki.elonen.SimpleWebServer.java
org.droidupnp.DrawerFragment.java
org.droidupnp.Main.java
org.droidupnp.controller.cling.ContentDirectoryCommand.java
org.droidupnp.controller.cling.Factory.java
org.droidupnp.controller.cling.RendererCommand.java
org.droidupnp.controller.cling.ServiceController.java
org.droidupnp.controller.cling.ServiceListener.java
org.droidupnp.controller.upnp.IUpnpServiceController.java
org.droidupnp.controller.upnp.UpnpDebugListener.java
org.droidupnp.model.CObservable.java
org.droidupnp.model.cling.CDevice.java
org.droidupnp.model.cling.CRegistryListener.java
org.droidupnp.model.cling.RendererState.java
org.droidupnp.model.cling.TrackMetadata.java
org.droidupnp.model.cling.UpnpRegistry.java
org.droidupnp.model.cling.UpnpServiceController.java
org.droidupnp.model.cling.UpnpService.java
org.droidupnp.model.cling.didl.ClingAudioItem.java
org.droidupnp.model.cling.didl.ClingDIDLContainer.java
org.droidupnp.model.cling.didl.ClingDIDLItem.java
org.droidupnp.model.cling.didl.ClingDIDLObject.java
org.droidupnp.model.cling.didl.ClingDIDLParentContainer.java
org.droidupnp.model.cling.didl.ClingImageItem.java
org.droidupnp.model.cling.didl.ClingVideoItem.java
org.droidupnp.model.cling.localContent.AlbumContainer.java
org.droidupnp.model.cling.localContent.ArtistContainer.java
org.droidupnp.model.cling.localContent.AudioContainer.java
org.droidupnp.model.cling.localContent.CustomContainer.java
org.droidupnp.model.cling.localContent.DynamicContainer.java
org.droidupnp.model.cling.localContent.ImageContainer.java
org.droidupnp.model.cling.localContent.VideoContainer.java
org.droidupnp.model.mediaserver.ContentDirectoryService.java
org.droidupnp.model.mediaserver.MediaServer.java
org.droidupnp.model.upnp.ARendererState.java
org.droidupnp.model.upnp.CallableContentDirectoryFilter.java
org.droidupnp.model.upnp.CallableRendererFilter.java
org.droidupnp.model.upnp.ContentDirectoryDiscovery.java
org.droidupnp.model.upnp.DeviceDiscovery.java
org.droidupnp.model.upnp.DeviceListener.java
org.droidupnp.model.upnp.ICallableFilter.java
org.droidupnp.model.upnp.IContentDirectoryCommand.java
org.droidupnp.model.upnp.IDeviceDiscoveryObserver.java
org.droidupnp.model.upnp.IFactory.java
org.droidupnp.model.upnp.IRegistryListener.java
org.droidupnp.model.upnp.IRendererCommand.java
org.droidupnp.model.upnp.IRendererState.java
org.droidupnp.model.upnp.IServiceListener.java
org.droidupnp.model.upnp.IUpnpDevice.java
org.droidupnp.model.upnp.IUpnpRegistry.java
org.droidupnp.model.upnp.PeeringConnectionManager.java
org.droidupnp.model.upnp.RendererDiscovery.java
org.droidupnp.model.upnp.didl.DIDLDevice.java
org.droidupnp.model.upnp.didl.IDIDLContainer.java
org.droidupnp.model.upnp.didl.IDIDLItem.java
org.droidupnp.model.upnp.didl.IDIDLObject.java
org.droidupnp.model.upnp.didl.IDIDLParentContainer.java
org.droidupnp.view.ContentDirectoryDeviceFragment.java
org.droidupnp.view.ContentDirectoryDialog.java
org.droidupnp.view.ContentDirectoryEnabler.java
org.droidupnp.view.ContentDirectoryFragment.java
org.droidupnp.view.Content.java
org.droidupnp.view.DIDLObjectDisplay.java
org.droidupnp.view.DeviceDisplay.java
org.droidupnp.view.DeviceFragment.java
org.droidupnp.view.DeviceInfoDialog.java
org.droidupnp.view.PlaylistFragment.java
org.droidupnp.view.RendererDeviceFragment.java
org.droidupnp.view.RendererDialog.java
org.droidupnp.view.RendererFragment.java
org.droidupnp.view.ServiceDiscoveryFragment.java
org.droidupnp.view.SettingsActivity.java
org.droidupnp.view.UpnpDeviceListFragment.java