Added proper screen rotation handling.

This commit is contained in:
Felix Ableitner 2013-10-07 16:40:26 +02:00
parent 838ad69360
commit 8ec6b90e92
6 changed files with 227 additions and 60 deletions

View file

@ -33,6 +33,7 @@ import org.teleal.cling.support.model.item.Item;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter; import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.app.FragmentTransaction; import android.support.v4.app.FragmentTransaction;
import android.support.v4.view.ViewPager; import android.support.v4.view.ViewPager;
@ -66,7 +67,7 @@ public class MainActivity extends ActionBarActivity {
public Fragment getItem(int position) { public Fragment getItem(int position) {
switch (position) { switch (position) {
case 0: return mServerFragment; case 0: return mServerFragment;
case 1: return mRendererFragment; case 1: return mRouteFragment;
default: return null; default: return null;
} }
} }
@ -78,9 +79,9 @@ public class MainActivity extends ActionBarActivity {
}; };
private ServerFragment mServerFragment = new ServerFragment(); private ServerFragment mServerFragment;
private RouteFragment mRendererFragment = new RouteFragment(); private RouteFragment mRouteFragment;
ViewPager mViewPager; ViewPager mViewPager;
@ -126,6 +127,29 @@ public class MainActivity extends ActionBarActivity {
actionBar.addTab(actionBar.newTab() actionBar.addTab(actionBar.newTab()
.setText(R.string.title_renderer) .setText(R.string.title_renderer)
.setTabListener(tabListener)); .setTabListener(tabListener));
if (savedInstanceState != null) {
FragmentManager fm = getSupportFragmentManager();
mServerFragment = (ServerFragment) fm.getFragment(
savedInstanceState, ServerFragment.class.getName());
mRouteFragment = (RouteFragment) fm.getFragment(
savedInstanceState, RouteFragment.class.getName());
}
else {
mServerFragment = new ServerFragment();
mRouteFragment = new RouteFragment();
}
}
/**
* Saves fragments.
*/
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
FragmentManager fm = getSupportFragmentManager();
fm.putFragment(outState, ServerFragment.class.getName(), mServerFragment);
fm.putFragment(outState, RouteFragment.class.getName(), mRouteFragment);
} }
/** /**
@ -148,11 +172,11 @@ public class MainActivity extends ActionBarActivity {
switch (event.getKeyCode()) { switch (event.getKeyCode()) {
case KeyEvent.KEYCODE_VOLUME_UP: case KeyEvent.KEYCODE_VOLUME_UP:
if (event.getAction() == KeyEvent.ACTION_DOWN) if (event.getAction() == KeyEvent.ACTION_DOWN)
mRendererFragment.increaseVolume(); mRouteFragment.increaseVolume();
return true; return true;
case KeyEvent.KEYCODE_VOLUME_DOWN: case KeyEvent.KEYCODE_VOLUME_DOWN:
if (event.getAction() == KeyEvent.ACTION_DOWN) if (event.getAction() == KeyEvent.ACTION_DOWN)
mRendererFragment.decreaseVolume(); mRouteFragment.decreaseVolume();
return true; return true;
default: default:
return super.dispatchKeyEvent(event); return super.dispatchKeyEvent(event);
@ -164,7 +188,7 @@ public class MainActivity extends ActionBarActivity {
*/ */
public void play(List<Item> playlist, int start) { public void play(List<Item> playlist, int start) {
mViewPager.setCurrentItem(1); mViewPager.setCurrentItem(1);
mRendererFragment.play(playlist, start); mRouteFragment.play(playlist, start);
} }
} }

View file

@ -107,7 +107,8 @@ public class RouteFragment extends MediaRouteDiscoveryFragment implements
public void onServiceConnected(ComponentName className, IBinder service) { public void onServiceConnected(ComponentName className, IBinder service) {
mMediaRouterPlayService = (MediaRouterPlayServiceBinder) service; mMediaRouterPlayService = (MediaRouterPlayServiceBinder) service;
mMediaRouterPlayService.getService().setRendererFragment(RouteFragment.this); mMediaRouterPlayService.getService().setRouterFragment(RouteFragment.this);
mPlaylistAdapter.addAll(mMediaRouterPlayService.getService().getPlaylist());
} }
public void onServiceDisconnected(ComponentName className) { public void onServiceDisconnected(ComponentName className) {
@ -140,6 +141,8 @@ public class RouteFragment extends MediaRouteDiscoveryFragment implements
super.onActivityCreated(savedInstanceState); super.onActivityCreated(savedInstanceState);
mRouteAdapter = new RouteAdapter(getActivity()); mRouteAdapter = new RouteAdapter(getActivity());
mRouteAdapter.addAll(MediaRouter.getInstance(getActivity()).getRoutes());
mRouteAdapter.remove(MediaRouter.getInstance(getActivity()).getDefaultRoute());
mPlaylistAdapter = new FileArrayAdapter(getActivity()); mPlaylistAdapter = new FileArrayAdapter(getActivity());
mListView = (ListView) getView().findViewById(R.id.listview); mListView = (ListView) getView().findViewById(R.id.listview);
@ -163,11 +166,36 @@ public class RouteFragment extends MediaRouteDiscoveryFragment implements
mPlayPause.setOnClickListener(this); mPlayPause.setOnClickListener(this);
mPlayPause.setImageResource(R.drawable.ic_media_play); mPlayPause.setImageResource(R.drawable.ic_media_play);
getActivity().bindService( getActivity().getApplicationContext().startService(
new Intent(getActivity(), MediaRouterPlayService.class));
getActivity().getApplicationContext().bindService(
new Intent(getActivity(), MediaRouterPlayService.class), new Intent(getActivity(), MediaRouterPlayService.class),
mPlayServiceConnection, mPlayServiceConnection,
Context.BIND_AUTO_CREATE Context.BIND_AUTO_CREATE
); );
if (savedInstanceState != null) {
mListView.onRestoreInstanceState(savedInstanceState.getParcelable("list_state"));
if (savedInstanceState.getBoolean("route_selected")) {
mRouteSelected = true;
mListView.setAdapter(mPlaylistAdapter);
mControls.setVisibility(View.VISIBLE);
}
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean("route_selected", mRouteSelected);
outState.putParcelable("list_state", mListView.onSaveInstanceState());
}
@Override
public void onDestroy() {
super.onDestroy();
getActivity().getApplicationContext().unbindService(mPlayServiceConnection);
} }
/** /**
@ -241,9 +269,7 @@ public class RouteFragment extends MediaRouteDiscoveryFragment implements
mRouteSelected = true; mRouteSelected = true;
mListView.setAdapter(mPlaylistAdapter); mListView.setAdapter(mPlaylistAdapter);
mControls.setVisibility(View.VISIBLE); mControls.setVisibility(View.VISIBLE);
if (mStartPlayingOnSelect == -1) if (mStartPlayingOnSelect != -1) {
mPlaylistAdapter.clear();
else {
mMediaRouterPlayService.getService().play(mStartPlayingOnSelect); mMediaRouterPlayService.getService().play(mStartPlayingOnSelect);
mStartPlayingOnSelect = -1; mStartPlayingOnSelect = -1;
} }
@ -256,7 +282,7 @@ public class RouteFragment extends MediaRouteDiscoveryFragment implements
* Sets colored background on the item that is currently playing. * Sets colored background on the item that is currently playing.
*/ */
private void enableTrackHighlight() { private void enableTrackHighlight() {
if (mListView.getAdapter() == mRouteAdapter) if (mListView.getAdapter() == mRouteAdapter || mMediaRouterPlayService == null || !isVisible())
return; return;
disableTrackHighlight(); disableTrackHighlight();

View file

@ -31,18 +31,28 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Stack; import java.util.Stack;
import org.teleal.cling.android.AndroidUpnpService;
import org.teleal.cling.android.AndroidUpnpServiceImpl;
import org.teleal.cling.model.action.ActionInvocation; import org.teleal.cling.model.action.ActionInvocation;
import org.teleal.cling.model.message.UpnpResponse; import org.teleal.cling.model.message.UpnpResponse;
import org.teleal.cling.model.meta.Device; 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.meta.Service;
import org.teleal.cling.model.types.ServiceType; import org.teleal.cling.model.types.ServiceType;
import org.teleal.cling.model.types.UDN;
import org.teleal.cling.support.contentdirectory.callback.Browse; import org.teleal.cling.support.contentdirectory.callback.Browse;
import org.teleal.cling.support.model.BrowseFlag; import org.teleal.cling.support.model.BrowseFlag;
import org.teleal.cling.support.model.DIDLContent; import org.teleal.cling.support.model.DIDLContent;
import org.teleal.cling.support.model.container.Container; import org.teleal.cling.support.model.container.Container;
import org.teleal.cling.support.model.item.Item; import org.teleal.cling.support.model.item.Item;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle; import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcelable; import android.os.Parcelable;
import android.support.v4.app.ListFragment; import android.support.v4.app.ListFragment;
import android.util.Log; import android.util.Log;
@ -50,7 +60,6 @@ import android.view.View;
import android.widget.ListView; import android.widget.ListView;
import com.github.nutomic.controldlna.gui.MainActivity.OnBackPressedListener; import com.github.nutomic.controldlna.gui.MainActivity.OnBackPressedListener;
import com.github.nutomic.controldlna.upnp.UpnpController;
import com.github.nutomic.controldlna.utility.DeviceArrayAdapter; import com.github.nutomic.controldlna.utility.DeviceArrayAdapter;
import com.github.nutomic.controldlna.utility.FileArrayAdapter; import com.github.nutomic.controldlna.utility.FileArrayAdapter;
@ -78,6 +87,8 @@ public class ServerFragment extends ListFragment implements OnBackPressedListene
*/ */
private Device<?, ?, ?> mCurrentServer; private Device<?, ?, ?> mCurrentServer;
private String mRestoreServer;
/** /**
* ListView adapter for showing a list of files/folders. * ListView adapter for showing a list of files/folders.
*/ */
@ -94,10 +105,40 @@ public class ServerFragment extends ListFragment implements OnBackPressedListene
*/ */
private Stack<Parcelable> mListState = new Stack<Parcelable>(); private Stack<Parcelable> mListState = new Stack<Parcelable>();
protected AndroidUpnpService mUpnpService;
private ServiceConnection mUpnpServiceConnection = new ServiceConnection() {
/** /**
* Manages all UPNP connections including playback. * Registers DeviceListener, adds known devices and starts search if requested.
*/ */
private UpnpController mController = new UpnpController(); public void onServiceConnected(ComponentName className, IBinder service) {
mUpnpService = (AndroidUpnpService) service;
mUpnpService.getRegistry().addListener(mServerAdapter);
for (Device<?, ?, ?> d : mUpnpService.getControlPoint().getRegistry().getDevices()) {
if (d instanceof LocalDevice)
mServerAdapter.localDeviceAdded(mUpnpService.getRegistry(), (LocalDevice) d);
else
mServerAdapter.remoteDeviceAdded(mUpnpService.getRegistry(), (RemoteDevice) d);
}
Log.i(TAG, "Starting device search");
mUpnpService.getControlPoint().search();
if (mRestoreServer != null) {
mCurrentServer = mUpnpService.getControlPoint().getRegistry()
.getDevice(new UDN(mRestoreServer.replace("uuid:", "")), false);
if (mCurrentServer != null) {
setListAdapter(mFileAdapter);
getFiles(true);
}
getListView().onRestoreInstanceState(mListState.lastElement());
}
}
public void onServiceDisconnected(ComponentName className) {
mUpnpService = null;
}
};
/** /**
* Initializes ListView adapters, launches Cling UPNP service. * Initializes ListView adapters, launches Cling UPNP service.
@ -110,26 +151,44 @@ public class ServerFragment extends ListFragment implements OnBackPressedListene
mServerAdapter = new DeviceArrayAdapter( mServerAdapter = new DeviceArrayAdapter(
getActivity(), DeviceArrayAdapter.SERVER); getActivity(), DeviceArrayAdapter.SERVER);
setListAdapter(mServerAdapter); setListAdapter(mServerAdapter);
mController.open(getActivity()); getActivity().getApplicationContext().bindService(
mController.addCallback(mServerAdapter); new Intent(getActivity(), AndroidUpnpServiceImpl.class),
mUpnpServiceConnection,
Context.BIND_AUTO_CREATE
);
if (savedInstanceState != null) {
mRestoreServer = savedInstanceState.getString("current_server");
mCurrentPath.addAll(savedInstanceState.getStringArrayList("path"));
mListState.addAll(savedInstanceState.getParcelableArrayList("list_state"));
}
else
mListState.push(getListView().onSaveInstanceState());
} }
@Override @Override
public void onResume() { public void onSaveInstanceState(Bundle outState) {
super.onResume(); super.onSaveInstanceState(outState);
mController.startSearch(); outState.putString("current_server", (mCurrentServer != null)
? mCurrentServer.getIdentity().getUdn().toString()
: "");
outState.putStringArrayList("path", new ArrayList<String>(mCurrentPath));
mListState.pop();
mListState.push(getListView().onSaveInstanceState());
outState.putParcelableArrayList("list_state", new ArrayList<Parcelable>(mListState));
} }
@Override @Override
public void onPause() { public void onPause() {
super.onPause(); super.onPause();
mController.stopSearch(); mListState.pop();
mListState.push(getListView().onSaveInstanceState());
} }
@Override @Override
public void onDestroy() { public void onDestroy() {
super.onDestroy(); super.onDestroy();
mController.close(getActivity()); getActivity().getApplicationContext().unbindService(mUpnpServiceConnection);
} }
/** /**
@ -175,7 +234,7 @@ public class ServerFragment extends ListFragment implements OnBackPressedListene
private void getFiles(final boolean restoreListState) { private void getFiles(final boolean restoreListState) {
Service<?, ?> service = mCurrentServer.findService( Service<?, ?> service = mCurrentServer.findService(
new ServiceType("schemas-upnp-org", "ContentDirectory")); new ServiceType("schemas-upnp-org", "ContentDirectory"));
mController.execute(new Browse(service, mUpnpService.getControlPoint().execute(new Browse(service,
mCurrentPath.peek(), BrowseFlag.DIRECT_CHILDREN) { mCurrentPath.peek(), BrowseFlag.DIRECT_CHILDREN) {
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
@ -192,7 +251,7 @@ public class ServerFragment extends ListFragment implements OnBackPressedListene
for (Item i : didl.getItems()) for (Item i : didl.getItems())
mFileAdapter.add(i); mFileAdapter.add(i);
if (restoreListState) if (restoreListState)
getListView().onRestoreInstanceState(mListState.pop()); getListView().onRestoreInstanceState(mListState.peek());
else else
getListView().setSelectionFromTop(0, 0); getListView().setSelectionFromTop(0, 0);
} }
@ -223,14 +282,14 @@ public class ServerFragment extends ListFragment implements OnBackPressedListene
return false; return false;
mCurrentPath.pop(); mCurrentPath.pop();
mListState.pop();
if (mCurrentPath.empty()) { if (mCurrentPath.empty()) {
setListAdapter(mServerAdapter); setListAdapter(mServerAdapter);
getListView().onRestoreInstanceState(mListState.pop()); getListView().onRestoreInstanceState(mListState.peek());
mCurrentServer = null; mCurrentServer = null;
} }
else { else
getFiles(true); getFiles(true);
}
return true; return true;
} }

View file

@ -90,10 +90,12 @@ public class MediaRouterPlayService extends Service {
private String mSessionId; private String mSessionId;
private WeakReference<RouteFragment> mRendererFragment = new WeakReference<RouteFragment>(null); private WeakReference<RouteFragment> mRouterFragment = new WeakReference<RouteFragment>(null);
private boolean mPollingStatus = false; private boolean mPollingStatus = false;
private boolean mBound;
/** /**
* Creates a notification after the icon bitmap is loaded. * Creates a notification after the icon bitmap is loaded.
*/ */
@ -118,10 +120,8 @@ public class MediaRouterPlayService extends Service {
.setLargeIcon(result) .setLargeIcon(result)
.setSmallIcon(R.drawable.ic_launcher) .setSmallIcon(R.drawable.ic_launcher)
.build(); .build();
NotificationManager notificationManager =
(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notificationManager.notify(NOTIFICATION_ID, notification);
notification.flags |= Notification.FLAG_ONGOING_EVENT; notification.flags |= Notification.FLAG_ONGOING_EVENT;
startForeground(NOTIFICATION_ID, notification);
} }
} }
@ -136,11 +136,28 @@ public class MediaRouterPlayService extends Service {
@Override @Override
public IBinder onBind(Intent intent) { public IBinder onBind(Intent intent) {
mBound = true;
return mBinder; return mBinder;
} }
public void setRendererFragment(RouteFragment rf) { /**
mRendererFragment = new WeakReference<RouteFragment>(rf); * Stops service after a delay if no media is playing (delay in case the
* fragment is recreated for screen rotation).
*/
@Override
public boolean onUnbind(Intent intent) {
new Handler().postDelayed(new Runnable() {
public void run() {
if (!mPollingStatus && !mBound)
stopSelf();
}
}, 5000);
mBound = false;
return super.onUnbind(intent);
}
public void setRouterFragment(RouteFragment rf) {
mRouterFragment = new WeakReference<RouteFragment>(rf);
} }
public void selectRoute(RouteInfo route) { public void selectRoute(RouteInfo route) {
@ -256,11 +273,6 @@ public class MediaRouterPlayService extends Service {
public int getCurrentTrack() { public int getCurrentTrack() {
return mCurrentTrack; return mCurrentTrack;
} }
public RouteInfo getDefaultRoute() {
return mMediaRouter.getDefaultRoute();
}
/** /**
* Requests playback information every second, as long as RendererFragment * Requests playback information every second, as long as RendererFragment
* is attached or media is playing. * is attached or media is playing.
@ -276,13 +288,15 @@ public class MediaRouterPlayService extends Service {
@Override @Override
public void onResult(Bundle data) { public void onResult(Bundle data) {
MediaItemStatus status = MediaItemStatus.fromBundle(data); MediaItemStatus status = MediaItemStatus.fromBundle(data);
if (mRendererFragment.get() != null) if (mRouterFragment.get() != null)
mRendererFragment.get().receivePlaybackStatus(status); mRouterFragment.get().receivePlaybackStatus(status);
if (status.getPlaybackState() == MediaItemStatus.PLAYBACK_STATE_FINISHED) { if (status.getPlaybackState() == MediaItemStatus.PLAYBACK_STATE_FINISHED) {
if (mCurrentTrack + 1 < mPlaylist.size()) if (mCurrentTrack + 1 < mPlaylist.size())
playNext(); playNext();
else { else {
if (!mBound)
stopSelf();
mPollingStatus = false; mPollingStatus = false;
NotificationManager notificationManager = NotificationManager notificationManager =
(NotificationManager) getSystemService(NOTIFICATION_SERVICE); (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
@ -310,4 +324,8 @@ public class MediaRouterPlayService extends Service {
mMediaRouter.getSelectedRoute().requestUpdateVolume(-1); mMediaRouter.getSelectedRoute().requestUpdateVolume(-1);
} }
public List<Item> getPlaylist() {
return mPlaylist;
}
} }

View file

@ -97,11 +97,8 @@ public class UpnpController implements RegistryListener {
else else
remoteDeviceAdded(mUpnpService.getRegistry(), (RemoteDevice) d); remoteDeviceAdded(mUpnpService.getRegistry(), (RemoteDevice) d);
} }
if (mStartSearchImmediately) { if (mStartSearchImmediately)
Log.i(TAG, "Starting device search"); startSearch();
mUpnpService.getControlPoint().search();
mStartSearchImmediately = false;
}
} }
public void onServiceDisconnected(ComponentName className) { public void onServiceDisconnected(ComponentName className) {
@ -139,6 +136,7 @@ public class UpnpController implements RegistryListener {
if (mUpnpService != null) { if (mUpnpService != null) {
Log.i(TAG, "Starting device search"); Log.i(TAG, "Starting device search");
mUpnpService.getControlPoint().search(); mUpnpService.getControlPoint().search();
mStartSearchImmediately = false;
} }
else else
mStartSearchImmediately = true; mStartSearchImmediately = true;

View file

@ -31,7 +31,10 @@ import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import org.teleal.cling.model.meta.Device; 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.RemoteDevice;
import org.teleal.cling.registry.Registry;
import org.teleal.cling.registry.RegistryListener;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
@ -43,7 +46,6 @@ import android.widget.ArrayAdapter;
import android.widget.TextView; import android.widget.TextView;
import com.github.nutomic.controldlna.R; import com.github.nutomic.controldlna.R;
import com.github.nutomic.controldlna.upnp.UpnpController.DeviceListenerCallback;
/** /**
@ -54,7 +56,7 @@ import com.github.nutomic.controldlna.upnp.UpnpController.DeviceListenerCallback
* *
*/ */
public class DeviceArrayAdapter extends ArrayAdapter<Device<?, ?, ?>> public class DeviceArrayAdapter extends ArrayAdapter<Device<?, ?, ?>>
implements DeviceListenerCallback { implements RegistryListener {
private static final String TAG = "DeviceArrayAdapter"; private static final String TAG = "DeviceArrayAdapter";
@ -106,8 +108,7 @@ public class DeviceArrayAdapter extends ArrayAdapter<Device<?, ?, ?>>
/** /**
* Adds a new device to the list if its type equals mDeviceType. * Adds a new device to the list if its type equals mDeviceType.
*/ */
@Override private void deviceAdded(final Device<?, ?, ?> device) {
public void deviceAdded(final Device<?, ?, ?> device) {
mActivity.runOnUiThread(new Runnable() { mActivity.runOnUiThread(new Runnable() {
@Override @Override
@ -121,8 +122,7 @@ public class DeviceArrayAdapter extends ArrayAdapter<Device<?, ?, ?>>
/** /**
* Removes the device from the list (if it is an element). * Removes the device from the list (if it is an element).
*/ */
@Override private void deviceRemoved(final Device<?, ?, ?> device) {
public void deviceRemoved(final Device<?, ?, ?> device) {
mActivity.runOnUiThread(new Runnable() { mActivity.runOnUiThread(new Runnable() {
@Override @Override
@ -133,8 +133,7 @@ public class DeviceArrayAdapter extends ArrayAdapter<Device<?, ?, ?>>
}); });
} }
@Override private void deviceUpdated(Device<?, ?, ?> device) {
public void deviceUpdated(Device<?, ?, ?> device) {
mActivity.runOnUiThread(new Runnable() { mActivity.runOnUiThread(new Runnable() {
@Override @Override
@ -143,4 +142,47 @@ public class DeviceArrayAdapter extends ArrayAdapter<Device<?, ?, ?>>
} }
}); });
} }
@Override
public void beforeShutdown(Registry registry) {
}
@Override
public void localDeviceAdded(Registry registry, LocalDevice device) {
deviceAdded(device);
}
@Override
public void localDeviceRemoved(Registry registry, LocalDevice device) {
deviceRemoved(device);
}
@Override
public void remoteDeviceAdded(Registry registry, RemoteDevice device) {
deviceAdded(device);
}
@Override
public void remoteDeviceDiscoveryFailed(Registry registry, RemoteDevice device,
Exception exception) {
Log.w(TAG, "Remote device discovery failed", exception);
}
@Override
public void remoteDeviceDiscoveryStarted(Registry registry, RemoteDevice device) {
}
@Override
public void remoteDeviceRemoved(Registry registry, RemoteDevice device) {
deviceRemoved(device);
}
@Override
public void remoteDeviceUpdated(Registry registry, RemoteDevice device) {
deviceUpdated(device);
}
@Override
public void afterShutdown() {
}
} }