Play single file.
This commit is contained in:
parent
d5ead78aa3
commit
063159b800
4 changed files with 329 additions and 49 deletions
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
Reference in a new issue