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

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
public void onBackPressed() {
if ((getSupportActionBar().getSelectedTab().getPosition() == 1) &&
!mServerFragment.onBackPressed())
OnBackPressedListener currentFragment = (OnBackPressedListener)
mSectionsPagerAdapter.getItem(mViewPager.getCurrentItem());
if (!currentFragment.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;
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.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";
/**
* 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.
* Null if media servers are shown.
*/
private Device<?, ?, ?> currentServer;
private Device<?, ?, ?> mCurrentServer;
/**
* 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
* behind that.
*/
private Stack<String> currentPath = new Stack<String>();
private Stack<String> mCurrentPath = new Stack<String>();
/**
* Cling UPNP service.
*/
private AndroidUpnpService upnpService;
private AndroidUpnpService mUpnpService;
/**
* Connection Cling to UPNP service.
*/
private ServiceConnection serviceConnection= new ServiceConnection() {
private ServiceConnection mServiceConnection= new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
upnpService = (AndroidUpnpService) service;
mUpnpService = (AndroidUpnpService) service;
Log.i(TAG, "Starting device search");
upnpService.getRegistry().addListener(registryListener);
upnpService.getControlPoint().search();
mUpnpService.getRegistry().addListener(registryListener);
mUpnpService.getControlPoint().search();
}
public void onServiceDisconnected(ComponentName className) {
upnpService = null;
mUpnpService = null;
}
};
@ -85,7 +94,7 @@ public class ServerFragment extends ListFragment {
@Override
public void remoteDeviceUpdated(Registry registry, RemoteDevice device) {
if (device == currentServer)
if (device == mCurrentServer)
getFiles();
}
@ -102,7 +111,7 @@ public class ServerFragment extends ListFragment {
@Override
public void remoteDeviceDiscoveryFailed(Registry registry,
RemoteDevice device, Exception exception) {
Log.w(TAG, "Device discovery failed");
Log.w(TAG, "Device discovery failed" + exception.getMessage());
}
@Override
@ -137,7 +146,7 @@ public class ServerFragment extends ListFragment {
@Override
public void run() {
if (device.getType().getType().equals("MediaServer"))
serverAdapter.add(device);
mServerAdapter.add(device);
}
});
}
@ -150,7 +159,7 @@ public class ServerFragment extends ListFragment {
@Override
public void run() {
serverAdapter.remove(device);
mServerAdapter.remove(device);
}
});
}
@ -162,14 +171,14 @@ public class ServerFragment extends ListFragment {
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
serverAdapter = new ServerArrayAdapter(getActivity());
fileAdapter = new FileArrayAdapter(getActivity());
mServerAdapter = new DeviceArrayAdapter(getActivity());
mFileAdapter = new FileArrayAdapter(getActivity());
setListAdapter(serverAdapter);
setListAdapter(mServerAdapter);
getActivity().getApplicationContext().bindService(
new Intent(getActivity(), AndroidUpnpServiceImpl.class),
serviceConnection,
mServiceConnection,
Context.BIND_AUTO_CREATE
);
}
@ -180,9 +189,9 @@ public class ServerFragment extends ListFragment {
@Override
public void onDestroy() {
super.onDestroy();
if (upnpService != null)
upnpService.getRegistry().removeListener(registryListener);
getActivity().getApplicationContext().unbindService(serviceConnection);
if (mUpnpService != null)
mUpnpService.getRegistry().removeListener(registryListener);
getActivity().getApplicationContext().unbindService(mServiceConnection);
}
/**
@ -190,15 +199,20 @@ public class ServerFragment extends ListFragment {
*/
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
if (getListAdapter() == serverAdapter) {
setListAdapter(fileAdapter);
currentServer = serverAdapter.getItem(position);
if (getListAdapter() == mServerAdapter) {
setListAdapter(mFileAdapter);
mCurrentServer = mServerAdapter.getItem(position);
// Root directory.
getFiles("0");
}
else if (getListAdapter() == fileAdapter) {
if (fileAdapter.getItem(position) instanceof Container) {
getFiles(((Container) fileAdapter.getItem(position)).getId());
else if (getListAdapter() == mFileAdapter) {
if (mFileAdapter.getItem(position) instanceof Container) {
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.
*/
private void getFiles(String directory) {
currentPath.push(directory);
mCurrentPath.push(directory);
getFiles();
}
@ -215,10 +229,10 @@ public class ServerFragment extends ListFragment {
* Displays the current directory on the ListView.
*/
private void getFiles() {
Service<?, ?> service = currentServer.findService(
Service<?, ?> service = mCurrentServer.findService(
new ServiceType("schemas-upnp-org", "ContentDirectory"));
upnpService.getControlPoint().execute(new Browse(service,
currentPath.peek(), BrowseFlag.DIRECT_CHILDREN) {
mUpnpService.getControlPoint().execute(new Browse(service,
mCurrentPath.peek(), BrowseFlag.DIRECT_CHILDREN) {
@SuppressWarnings("rawtypes")
@Override
@ -228,11 +242,11 @@ public class ServerFragment extends ListFragment {
@Override
public void run() {
fileAdapter.clear();
mFileAdapter.clear();
for (Container c : didl.getContainers())
fileAdapter.add(c);
mFileAdapter.add(c);
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
* browsing mode).
*
* @return True if button press was handled.
*/
public boolean onBackPressed() {
if (getListAdapter() == serverAdapter)
if (getListAdapter() == mServerAdapter)
return false;
currentPath.pop();
if (currentPath.empty()) {
setListAdapter(serverAdapter);
currentServer = null;
mCurrentPath.pop();
if (mCurrentPath.empty()) {
setListAdapter(mServerAdapter);
mCurrentServer = null;
}
else {
getFiles();