Set play/paused state only through events.

This commit is contained in:
Felix Ableitner 2013-06-06 10:44:03 +02:00
parent a44f88729c
commit d8660afaeb
3 changed files with 127 additions and 70 deletions

View file

@ -1,5 +1,7 @@
package com.github.nutomic.controldlna;
import org.teleal.cling.support.model.item.Item;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
@ -133,9 +135,12 @@ public class MainActivity extends SherlockFragmentActivity implements
super.onBackPressed();
}
public void play(String uri) {
/**
* Utility function to call RendererFragment.play from ServerFragment.
*/
public void play(Item[] playlist, int start) {
getSupportActionBar().selectTab(getSupportActionBar().getTabAt(0));
mRendererFragment.play(uri);
mRendererFragment.play(playlist, start);
}
}

View file

@ -1,19 +1,29 @@
package com.github.nutomic.controldlna;
import java.util.Map;
import org.teleal.cling.android.AndroidUpnpService;
import org.teleal.cling.android.AndroidUpnpServiceImpl;
import org.teleal.cling.controlpoint.SubscriptionCallback;
import org.teleal.cling.model.action.ActionInvocation;
import org.teleal.cling.model.gena.CancelReason;
import org.teleal.cling.model.gena.GENASubscription;
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.state.StateVariableValue;
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;
import org.teleal.cling.support.avtransport.callback.Stop;
import org.teleal.cling.support.avtransport.lastchange.AVTransportLastChangeParser;
import org.teleal.cling.support.avtransport.lastchange.AVTransportVariable;
import org.teleal.cling.support.lastchange.LastChange;
import org.teleal.cling.support.model.item.Item;
import android.content.ComponentName;
import android.content.Context;
@ -52,21 +62,26 @@ public class RendererFragment extends Fragment implements
private boolean mPlaying = false;
private Item[] mPlaylist;
/**
* ListView adapter of media renderers.
*/
private DeviceArrayAdapter mRendererAdapter;
private FileArrayAdapter mPlaylistAdapter;
/**
* The media renderer that is currently active.
*/
@SuppressWarnings("rawtypes")
private Device mCurrentRenderer;
private Device<?, ?, ?> mCurrentRenderer;
/**
* Stores uri that is to be played if no renderer is selected.
* First track to be played when a renderer is selected (-1 for none).
*/
private String mCachedPlayUri = "";
private int mCachedStart = -1;
private SubscriptionCallback mSubscriptionCallback;
/**
* Cling UPNP service.
@ -199,7 +214,7 @@ public class RendererFragment extends Fragment implements
@Override
public void onPause() {
super.onPause();
mCachedPlayUri = "";
mCachedStart = -1;
}
/**
@ -214,16 +229,20 @@ public class RendererFragment extends Fragment implements
}
/**
* Plays an URI to a media renderer. If none is selected, the URI is
* cached and played after selecting one.
* Plays the URIs in playlist to the current renderer, or caches parameters
* until a renderer is selected.
*
* @param playlist Array of URIs to play.
* @param start Index of the URI which should be played first.
*/
void play(String uri) {
Log.d(TAG, uri);
public void play(Item[] playlist, final int start) {
mPlaylist = playlist;
if (mCurrentRenderer != null) {
mListView.setAdapter(mPlaylistAdapter);
final Service<?, ?> service = mCurrentRenderer.findService(
new ServiceType("schemas-upnp-org", "AVTransport"));
mUpnpService.getControlPoint().execute(new SetAVTransportURI(service,
uri, "NO METADATA") {
playlist[start].getFirstResource().getValue(), "NO METADATA") {
@SuppressWarnings("rawtypes")
@Override
public void failure(ActionInvocation invocation,
@ -235,15 +254,12 @@ public class RendererFragment extends Fragment implements
@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);
}
@Override
public void success(ActionInvocation invocation) {
playbackStarted();
}
});
}
});
@ -251,7 +267,7 @@ public class RendererFragment extends Fragment implements
else {
Toast.makeText(getActivity(), "Please select a renderer.",
Toast.LENGTH_SHORT).show();
mCachedPlayUri = uri;
mCachedStart = start;
}
}
@ -262,12 +278,85 @@ public class RendererFragment extends Fragment implements
public void onItemClick(AdapterView<?> a, View v, int position, long id) {
if (mCurrentRenderer == null) {
mCurrentRenderer = mRendererAdapter.getItem(position);
mListView.setAdapter(null);
mPlayPause.setVisibility(View.VISIBLE);
if (!mCachedPlayUri.equals("")) {
play(mCachedPlayUri);
mCachedPlayUri = "";
Service<?, ?> service = mCurrentRenderer.findService(
new ServiceType("schemas-upnp-org", "AVTransport"));
mSubscriptionCallback = new SubscriptionCallback(service, 600) {
@SuppressWarnings("rawtypes")
@Override
protected void established(GENASubscription sub) {
}
@SuppressWarnings("rawtypes")
@Override
protected void ended(GENASubscription sub, CancelReason reason,
UpnpResponse response) {
}
@SuppressWarnings("rawtypes")
@Override
protected void eventReceived(GENASubscription sub) {
@SuppressWarnings("unchecked")
Map<String, StateVariableValue> m = sub.getCurrentValues();
try {
LastChange lastChange = new LastChange(
new AVTransportLastChangeParser(),
m.get("LastChange").toString());
switch (lastChange.getEventedValue(0,
AVTransportVariable.TransportState.class)
.getValue()) {
case PLAYING:
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
mPlayPause.setText(R.string.pause);
mPlaying = true;
Log.d(TAG, "play");
}
});
break;
case PAUSED_PLAYBACK:
// fallthrough
case STOPPED:
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
mPlayPause.setText(R.string.play);
mPlaying = false;
Log.d(TAG, "stop");
}
});
break;
default:
}
} catch (Exception e) {
e.printStackTrace();
}
}
@SuppressWarnings("rawtypes")
@Override
protected void eventsMissed(GENASubscription sub, int numberOfMissedEvents) {
}
@SuppressWarnings("rawtypes")
@Override
protected void failed(GENASubscription sub, UpnpResponse responseStatus,
Exception exception, String defaultMsg) {
Log.d(TAG, defaultMsg);
}
};
mUpnpService.getControlPoint().execute(mSubscriptionCallback);
if (mCachedStart != -1) {
play(mPlaylist, mCachedStart);
mCachedStart = -1;
}
mListView.setAdapter(mPlaylistAdapter);
mPlayPause.setVisibility(View.VISIBLE);
}
}
@ -277,9 +366,11 @@ public class RendererFragment extends Fragment implements
@Override
public boolean onBackPressed() {
if (mCurrentRenderer != null) {
mListView.setAdapter(mRendererAdapter);
mCurrentRenderer = null;
mPlayPause.setVisibility(View.GONE);
mSubscriptionCallback.end();
mListView.setAdapter(mRendererAdapter);
mPlayPause.setVisibility(View.GONE);
return true;
}
return false;
@ -310,17 +401,8 @@ public class RendererFragment extends Fragment implements
UpnpResponse operation, String defaultMessage) {
Log.w(TAG, "Stop failed: " + defaultMessage);
}
@Override
public void success(ActionInvocation invocation) {
playbackPaused();
};
});
}
@SuppressWarnings("rawtypes")
@Override
public void success(ActionInvocation invocation) {
playbackPaused();
};
});
} else {
mUpnpService.getControlPoint().execute(new Play(service) {
@ -331,44 +413,9 @@ public class RendererFragment extends Fragment implements
UpnpResponse operation, String defaultMessage) {
Log.w(TAG, "Play failed: " + defaultMessage);
}
@SuppressWarnings("rawtypes")
@Override
public void success(ActionInvocation invocation) {
playbackStarted();
};
});
}
}
}
/**
* Sets button text and playing attribute.
* Call this after pausing/stopping playback.
*/
private void playbackPaused() {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
mPlaying = false;
mPlayPause.setText(R.string.play);
}
});
}
/**
* Sets button text and playing attribute.
* Call this after starting playback.
*/
private void playbackStarted() {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
mPlaying = true;
mPlayPause.setText(R.string.pause);
}
});
}
}

View file

@ -211,9 +211,14 @@ public class ServerFragment extends ListFragment implements OnBackPressedListene
getFiles(((Container) mFileAdapter.getItem(position)).getId());
}
else {
Item[] playlist = new Item[mFileAdapter.getCount()];
for (int i = 0; i < mFileAdapter.getCount(); i++) {
if (mFileAdapter.getItem(i) instanceof Item) {
playlist[i] = (Item) mFileAdapter.getItem(position);
}
}
MainActivity activity = (MainActivity) getActivity();
activity.play(mFileAdapter.getItem(position)
.getFirstResource().getValue());
activity.play(playlist, position);
}
}
}