Play single file.

This commit is contained in:
Felix Ableitner 2013-06-02 17:43:21 +02:00
parent d5ead78aa3
commit 063159b800
4 changed files with 329 additions and 49 deletions

View file

@ -9,9 +9,9 @@ import android.view.ViewGroup;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import android.widget.TextView; import android.widget.TextView;
public class ServerArrayAdapter extends ArrayAdapter<Device<?, ?, ?>> { public class DeviceArrayAdapter extends ArrayAdapter<Device<?, ?, ?>> {
public ServerArrayAdapter(Context context) { public DeviceArrayAdapter(Context context) {
super(context, android.R.layout.simple_list_item_1); super(context, android.R.layout.simple_list_item_1);
} }

View file

@ -112,13 +112,30 @@ public class MainActivity extends SherlockFragmentActivity implements
} }
/** /**
* Forwards to ServerFragment if it is active. * Listener for the 'back' key.
*/
public interface OnBackPressedListener {
/**
* Returns true if the press was consumed, false otherwise.
*/
public boolean onBackPressed();
}
/**
* Forwards back press to active Fragment.
*/ */
@Override @Override
public void onBackPressed() { public void onBackPressed() {
if ((getSupportActionBar().getSelectedTab().getPosition() == 1) && OnBackPressedListener currentFragment = (OnBackPressedListener)
!mServerFragment.onBackPressed()) mSectionsPagerAdapter.getItem(mViewPager.getCurrentItem());
if (!currentFragment.onBackPressed())
super.onBackPressed(); super.onBackPressed();
} }
public void play(String uri) {
getSupportActionBar().selectTab(getSupportActionBar().getTabAt(0));
mRendererFragment.play(uri);
}
} }

View file

@ -1,7 +1,258 @@
package com.github.nutomic.controldlna; package com.github.nutomic.controldlna;
import android.support.v4.app.Fragment; import org.teleal.cling.android.AndroidUpnpService;
import org.teleal.cling.android.AndroidUpnpServiceImpl;
import org.teleal.cling.model.action.ActionInvocation;
import org.teleal.cling.model.message.UpnpResponse;
import org.teleal.cling.model.meta.Device;
import org.teleal.cling.model.meta.LocalDevice;
import org.teleal.cling.model.meta.RemoteDevice;
import org.teleal.cling.model.meta.Service;
import org.teleal.cling.model.types.ServiceType;
import org.teleal.cling.registry.Registry;
import org.teleal.cling.registry.RegistryListener;
import org.teleal.cling.support.avtransport.callback.Play;
import org.teleal.cling.support.avtransport.callback.SetAVTransportURI;
public class RendererFragment extends Fragment { import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.support.v4.app.ListFragment;
import android.util.Log;
import android.view.View;
import android.widget.ListView;
import android.widget.Toast;
import com.github.nutomic.controldlna.MainActivity.OnBackPressedListener;
/**
* Shows a list of media servers, allowing to select one for playback.
*
* @author Felix
*
*/
public class RendererFragment extends ListFragment implements OnBackPressedListener {
private String TAG = "RendererFragment";
/**
* ListView adapter of media renderers.
*/
private DeviceArrayAdapter mRendererAdapter;
/**
* The media renderer that is currently active.
*/
@SuppressWarnings("rawtypes")
private Device mCurrentRenderer;
/**
* Stores uri that is to be played if no renderer is selected.
*/
private String mCachedPlayUri = "";
/**
* Cling UPNP service.
*/
private AndroidUpnpService mUpnpService;
/**
* Connection Cling to UPNP service.
*/
private ServiceConnection mServiceConnection= new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
mUpnpService = (AndroidUpnpService) service;
Log.i(TAG, "Starting device search");
mUpnpService.getRegistry().addListener(mRegistryListener);
mUpnpService.getControlPoint().search();
}
public void onServiceDisconnected(ComponentName className) {
mUpnpService = null;
}
};
/**
* Receives updates when devices are added or removed.
*/
private RegistryListener mRegistryListener = new RegistryListener() {
@Override
public void remoteDeviceUpdated(Registry registry, RemoteDevice device) {
}
@Override
public void remoteDeviceRemoved(Registry registry, RemoteDevice device) {
remove(device);
}
@Override
public void remoteDeviceDiscoveryStarted(Registry registry,
RemoteDevice device) {
}
@Override
public void remoteDeviceDiscoveryFailed(Registry registry,
RemoteDevice device, Exception exception) {
Log.w(TAG, "Device discovery failed" + exception.getMessage());
}
@Override
public void remoteDeviceAdded(Registry registry, RemoteDevice device) {
add(device);
}
@Override
public void localDeviceRemoved(Registry registry, LocalDevice device) {
remove(device);
}
@Override
public void localDeviceAdded(Registry registry, LocalDevice device) {
add(device);
}
@Override
public void beforeShutdown(Registry registry) {
}
@Override
public void afterShutdown() {
}
/**
* Add a device to the ListView.
*/
private void add(final Device<?, ?, ?> device) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
if (device.getType().getType().equals("MediaRenderer"))
mRendererAdapter.add(device);
}
});
}
/**
* Remove a device from the ListView.
*/
private void remove(final Device<?, ?, ?> device) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
mRendererAdapter.remove(device);
}
});
}
};
/**
* Initializes ListView adapters, launches Cling UPNP service.
*/
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mRendererAdapter = new DeviceArrayAdapter(getActivity());
setListAdapter(mRendererAdapter);
getActivity().getApplicationContext().bindService(
new Intent(getActivity(), AndroidUpnpServiceImpl.class),
mServiceConnection,
Context.BIND_AUTO_CREATE
);
}
/**
* Clears cached playback URI.
*/
@Override
public void onPause() {
super.onPause();
mCachedPlayUri = "";
}
/**
* Closes Cling UPNP service.
*/
@Override
public void onDestroy() {
super.onDestroy();
if (mUpnpService != null)
mUpnpService.getRegistry().removeListener(mRegistryListener);
getActivity().getApplicationContext().unbindService(mServiceConnection);
}
/**
* Plays an URI to a media renderer. If none is selected, the URI is
* cached and played after selecting one.
*/
void play(String uri) {
Log.d(TAG, uri);
if (mCurrentRenderer != null) {
final Service<?, ?> service = mCurrentRenderer.findService(
new ServiceType("schemas-upnp-org", "AVTransport"));
mUpnpService.getControlPoint().execute(new SetAVTransportURI(service,
uri, "NO METADATA") {
@SuppressWarnings("rawtypes")
@Override
public void failure(ActionInvocation invocation,
UpnpResponse operation, String defaultMsg) {
Log.w(TAG, "Playback failed: " + defaultMsg);
}
@SuppressWarnings("rawtypes")
@Override
public void success(ActionInvocation invocation) {
mUpnpService.getControlPoint().execute(new Play(service) {
@Override
public void failure(ActionInvocation invocation,
UpnpResponse operation, String defaultMsg) {
Log.w(TAG, "Playback failed: " + defaultMsg);
}
});
}
});
}
else {
Toast.makeText(getActivity(), "Please select a renderer.",
Toast.LENGTH_SHORT).show();
mCachedPlayUri = uri;
}
}
/**
* Selects a media renderer.
*/
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
if (mCurrentRenderer == null) {
mCurrentRenderer = mRendererAdapter.getItem(position);
setListAdapter(null);
if (!mCachedPlayUri.equals("")) {
play(mCachedPlayUri);
mCachedPlayUri = "";
}
}
}
/**
* Unselects current media renderer if one is selected.
*/
@Override
public boolean onBackPressed() {
if (mCurrentRenderer != null) {
setListAdapter(mRendererAdapter);
mCurrentRenderer = null;
return true;
}
return false;
}
} }

View file

@ -30,51 +30,60 @@ import android.util.Log;
import android.view.View; import android.view.View;
import android.widget.ListView; import android.widget.ListView;
public class ServerFragment extends ListFragment { import com.github.nutomic.controldlna.MainActivity.OnBackPressedListener;
/**
* Shows a list of media servers, upon selecting one, allows browsing theur
* directories.
*
* @author Felix
*
*/
public class ServerFragment extends ListFragment implements OnBackPressedListener {
private String TAG = "ServerFragment"; private String TAG = "ServerFragment";
/** /**
* ListView adapter for showing a list of DLNA media servers. * ListView adapter for showing a list of DLNA media servers.
*/ */
private ServerArrayAdapter serverAdapter; private DeviceArrayAdapter mServerAdapter;
/** /**
* Reference to the media server of which folders are currently shown. * Reference to the media server of which folders are currently shown.
* Null if media servers are shown. * Null if media servers are shown.
*/ */
private Device<?, ?, ?> currentServer; private Device<?, ?, ?> mCurrentServer;
/** /**
* ListView adapter for showing a list of files/folders. * ListView adapter for showing a list of files/folders.
*/ */
private FileArrayAdapter fileAdapter; private FileArrayAdapter mFileAdapter;
/** /**
* Holds path to current directory on top, paths for higher directories * Holds path to current directory on top, paths for higher directories
* behind that. * behind that.
*/ */
private Stack<String> currentPath = new Stack<String>(); private Stack<String> mCurrentPath = new Stack<String>();
/** /**
* Cling UPNP service. * Cling UPNP service.
*/ */
private AndroidUpnpService upnpService; private AndroidUpnpService mUpnpService;
/** /**
* Connection Cling to UPNP service. * Connection Cling to UPNP service.
*/ */
private ServiceConnection serviceConnection= new ServiceConnection() { private ServiceConnection mServiceConnection= new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) { public void onServiceConnected(ComponentName className, IBinder service) {
upnpService = (AndroidUpnpService) service; mUpnpService = (AndroidUpnpService) service;
Log.i(TAG, "Starting device search"); Log.i(TAG, "Starting device search");
upnpService.getRegistry().addListener(registryListener); mUpnpService.getRegistry().addListener(registryListener);
upnpService.getControlPoint().search(); mUpnpService.getControlPoint().search();
} }
public void onServiceDisconnected(ComponentName className) { public void onServiceDisconnected(ComponentName className) {
upnpService = null; mUpnpService = null;
} }
}; };
@ -85,7 +94,7 @@ public class ServerFragment extends ListFragment {
@Override @Override
public void remoteDeviceUpdated(Registry registry, RemoteDevice device) { public void remoteDeviceUpdated(Registry registry, RemoteDevice device) {
if (device == currentServer) if (device == mCurrentServer)
getFiles(); getFiles();
} }
@ -102,7 +111,7 @@ public class ServerFragment extends ListFragment {
@Override @Override
public void remoteDeviceDiscoveryFailed(Registry registry, public void remoteDeviceDiscoveryFailed(Registry registry,
RemoteDevice device, Exception exception) { RemoteDevice device, Exception exception) {
Log.w(TAG, "Device discovery failed"); Log.w(TAG, "Device discovery failed" + exception.getMessage());
} }
@Override @Override
@ -137,7 +146,7 @@ public class ServerFragment extends ListFragment {
@Override @Override
public void run() { public void run() {
if (device.getType().getType().equals("MediaServer")) if (device.getType().getType().equals("MediaServer"))
serverAdapter.add(device); mServerAdapter.add(device);
} }
}); });
} }
@ -150,7 +159,7 @@ public class ServerFragment extends ListFragment {
@Override @Override
public void run() { public void run() {
serverAdapter.remove(device); mServerAdapter.remove(device);
} }
}); });
} }
@ -162,14 +171,14 @@ public class ServerFragment extends ListFragment {
@Override @Override
public void onActivityCreated(Bundle savedInstanceState) { public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState); super.onActivityCreated(savedInstanceState);
serverAdapter = new ServerArrayAdapter(getActivity()); mServerAdapter = new DeviceArrayAdapter(getActivity());
fileAdapter = new FileArrayAdapter(getActivity()); mFileAdapter = new FileArrayAdapter(getActivity());
setListAdapter(serverAdapter); setListAdapter(mServerAdapter);
getActivity().getApplicationContext().bindService( getActivity().getApplicationContext().bindService(
new Intent(getActivity(), AndroidUpnpServiceImpl.class), new Intent(getActivity(), AndroidUpnpServiceImpl.class),
serviceConnection, mServiceConnection,
Context.BIND_AUTO_CREATE Context.BIND_AUTO_CREATE
); );
} }
@ -180,9 +189,9 @@ public class ServerFragment extends ListFragment {
@Override @Override
public void onDestroy() { public void onDestroy() {
super.onDestroy(); super.onDestroy();
if (upnpService != null) if (mUpnpService != null)
upnpService.getRegistry().removeListener(registryListener); mUpnpService.getRegistry().removeListener(registryListener);
getActivity().getApplicationContext().unbindService(serviceConnection); getActivity().getApplicationContext().unbindService(mServiceConnection);
} }
/** /**
@ -190,15 +199,20 @@ public class ServerFragment extends ListFragment {
*/ */
@Override @Override
public void onListItemClick(ListView l, View v, int position, long id) { public void onListItemClick(ListView l, View v, int position, long id) {
if (getListAdapter() == serverAdapter) { if (getListAdapter() == mServerAdapter) {
setListAdapter(fileAdapter); setListAdapter(mFileAdapter);
currentServer = serverAdapter.getItem(position); mCurrentServer = mServerAdapter.getItem(position);
// Root directory. // Root directory.
getFiles("0"); getFiles("0");
} }
else if (getListAdapter() == fileAdapter) { else if (getListAdapter() == mFileAdapter) {
if (fileAdapter.getItem(position) instanceof Container) { if (mFileAdapter.getItem(position) instanceof Container) {
getFiles(((Container) fileAdapter.getItem(position)).getId()); getFiles(((Container) mFileAdapter.getItem(position)).getId());
}
else {
MainActivity activity = (MainActivity) getActivity();
activity.play(mFileAdapter.getItem(position)
.getFirstResource().getValue());
} }
} }
} }
@ -207,7 +221,7 @@ public class ServerFragment extends ListFragment {
* Opens a new directory and displays it. * Opens a new directory and displays it.
*/ */
private void getFiles(String directory) { private void getFiles(String directory) {
currentPath.push(directory); mCurrentPath.push(directory);
getFiles(); getFiles();
} }
@ -215,10 +229,10 @@ public class ServerFragment extends ListFragment {
* Displays the current directory on the ListView. * Displays the current directory on the ListView.
*/ */
private void getFiles() { private void getFiles() {
Service<?, ?> service = currentServer.findService( Service<?, ?> service = mCurrentServer.findService(
new ServiceType("schemas-upnp-org", "ContentDirectory")); new ServiceType("schemas-upnp-org", "ContentDirectory"));
upnpService.getControlPoint().execute(new Browse(service, mUpnpService.getControlPoint().execute(new Browse(service,
currentPath.peek(), BrowseFlag.DIRECT_CHILDREN) { mCurrentPath.peek(), BrowseFlag.DIRECT_CHILDREN) {
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
@Override @Override
@ -228,11 +242,11 @@ public class ServerFragment extends ListFragment {
@Override @Override
public void run() { public void run() {
fileAdapter.clear(); mFileAdapter.clear();
for (Container c : didl.getContainers()) for (Container c : didl.getContainers())
fileAdapter.add(c); mFileAdapter.add(c);
for (Item i : didl.getItems()) for (Item i : didl.getItems())
fileAdapter.add(i); mFileAdapter.add(i);
} }
}); });
} }
@ -255,16 +269,14 @@ public class ServerFragment extends ListFragment {
/** /**
* Handles back button press to traverse directories (while in directory * Handles back button press to traverse directories (while in directory
* browsing mode). * browsing mode).
*
* @return True if button press was handled.
*/ */
public boolean onBackPressed() { public boolean onBackPressed() {
if (getListAdapter() == serverAdapter) if (getListAdapter() == mServerAdapter)
return false; return false;
currentPath.pop(); mCurrentPath.pop();
if (currentPath.empty()) { if (mCurrentPath.empty()) {
setListAdapter(serverAdapter); setListAdapter(mServerAdapter);
currentServer = null; mCurrentServer = null;
} }
else { else {
getFiles(); getFiles();