diff --git a/src/com/github/nutomic/controldlna/gui/MainActivity.java b/src/com/github/nutomic/controldlna/gui/MainActivity.java index d50ecd9..ddb7b24 100644 --- a/src/com/github/nutomic/controldlna/gui/MainActivity.java +++ b/src/com/github/nutomic/controldlna/gui/MainActivity.java @@ -4,12 +4,12 @@ All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * Neither the name of the nor the + * Neither the name of the nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. @@ -61,66 +61,66 @@ import com.github.nutomic.controldlna.R; * */ public class MainActivity extends ActionBarActivity { - + /** * Interface which allows listening to "back" button presses. */ - public interface OnBackPressedListener { - boolean onBackPressed(); - } - - FragmentStatePagerAdapter mSectionsPagerAdapter = - new FragmentStatePagerAdapter(getSupportFragmentManager()) { + public interface OnBackPressedListener { + boolean onBackPressed(); + } - @Override - public Fragment getItem(int position) { - switch (position) { - case 0: return mServerFragment; - case 1: return mRouteFragment; - default: return null; - } - } + FragmentStatePagerAdapter mSectionsPagerAdapter = + new FragmentStatePagerAdapter(getSupportFragmentManager()) { - @Override - public int getCount() { - return 2; - } - - }; + @Override + public Fragment getItem(int position) { + switch (position) { + case 0: return mServerFragment; + case 1: return mRouteFragment; + default: return null; + } + } - private ServerFragment mServerFragment; - - private RouteFragment mRouteFragment; - - ViewPager mViewPager; + @Override + public int getCount() { + return 2; + } - /** - * Initializes tab navigation. If wifi is not connected, - * shows a warning dialog. - */ - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - final ActionBar actionBar = getSupportActionBar(); + }; - actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); - actionBar.setDisplayShowTitleEnabled(false); - actionBar.setDisplayShowHomeEnabled(false); - setContentView(R.layout.activity_main); - - mViewPager = (ViewPager) findViewById(R.id.pager); - mViewPager.setAdapter(mSectionsPagerAdapter); - mViewPager.setOnPageChangeListener( - new ViewPager.SimpleOnPageChangeListener() { - @Override - public void onPageSelected(int position) { - actionBar.setSelectedNavigationItem(position); - } - }); + private ServerFragment mServerFragment; - TabListener tabListener = new ActionBar.TabListener() { - public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) { - mViewPager.setCurrentItem(tab.getPosition()); - } + private RouteFragment mRouteFragment; + + ViewPager mViewPager; + + /** + * Initializes tab navigation. If wifi is not connected, + * shows a warning dialog. + */ + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + final ActionBar actionBar = getSupportActionBar(); + + actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); + actionBar.setDisplayShowTitleEnabled(false); + actionBar.setDisplayShowHomeEnabled(false); + setContentView(R.layout.activity_main); + + mViewPager = (ViewPager) findViewById(R.id.pager); + mViewPager.setAdapter(mSectionsPagerAdapter); + mViewPager.setOnPageChangeListener( + new ViewPager.SimpleOnPageChangeListener() { + @Override + public void onPageSelected(int position) { + actionBar.setSelectedNavigationItem(position); + } + }); + + TabListener tabListener = new ActionBar.TabListener() { + public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) { + mViewPager.setCurrentItem(tab.getPosition()); + } @Override public void onTabReselected(Tab arg0, FragmentTransaction arg1) { @@ -129,112 +129,112 @@ public class MainActivity extends ActionBarActivity { @Override public void onTabUnselected(Tab arg0, FragmentTransaction arg1) { } - }; + }; - actionBar.addTab(actionBar.newTab() - .setText(R.string.title_server) - .setTabListener(tabListener)); - actionBar.addTab(actionBar.newTab() - .setText(R.string.title_route) - .setTabListener(tabListener)); - - ConnectivityManager connManager = (ConnectivityManager) - getSystemService(CONNECTIVITY_SERVICE); - NetworkInfo wifi = connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI); - final SharedPreferences prefs = getSharedPreferences("preferences.db", 0); + actionBar.addTab(actionBar.newTab() + .setText(R.string.title_server) + .setTabListener(tabListener)); + actionBar.addTab(actionBar.newTab() + .setText(R.string.title_route) + .setTabListener(tabListener)); - if (!wifi.isConnected() && !prefs.getBoolean("wifi_skip_dialog", false)) { - View checkBoxView = View.inflate(this, R.layout.dialog_wifi_disabled, null); - CheckBox checkBox = (CheckBox) checkBoxView.findViewById(R.id.dont_show_again); - checkBox.setOnCheckedChangeListener(new OnCheckedChangeListener() { + ConnectivityManager connManager = (ConnectivityManager) + getSystemService(CONNECTIVITY_SERVICE); + NetworkInfo wifi = connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI); + final SharedPreferences prefs = getSharedPreferences("preferences.db", 0); - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - prefs.edit().putBoolean("wifi_skip_dialog", isChecked) - .commit(); - } - }); - - new AlertDialog.Builder(this) - .setView(checkBoxView) - .setTitle(R.string.warning_wifi_not_connected) - .setPositiveButton(android.R.string.ok, null) - .show(); - } - - if (savedInstanceState != null) { - FragmentManager fm = getSupportFragmentManager(); - mServerFragment = (ServerFragment) fm.getFragment( - savedInstanceState, ServerFragment.class.getName()); - mRouteFragment = (RouteFragment) fm.getFragment( - savedInstanceState, RouteFragment.class.getName()); - mViewPager.setCurrentItem(savedInstanceState.getInt("currentTab")); - } - else { - mServerFragment = new ServerFragment(); - mRouteFragment = new RouteFragment(); - } - onNewIntent(getIntent()); - } - - /** - * Displays the RouteFragment immediately (instead of ServerFragment). - */ + if (!wifi.isConnected() && !prefs.getBoolean("wifi_skip_dialog", false)) { + View checkBoxView = View.inflate(this, R.layout.dialog_wifi_disabled, null); + CheckBox checkBox = (CheckBox) checkBoxView.findViewById(R.id.dont_show_again); + checkBox.setOnCheckedChangeListener(new OnCheckedChangeListener() { + + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + prefs.edit().putBoolean("wifi_skip_dialog", isChecked) + .commit(); + } + }); + + new AlertDialog.Builder(this) + .setView(checkBoxView) + .setTitle(R.string.warning_wifi_not_connected) + .setPositiveButton(android.R.string.ok, null) + .show(); + } + + if (savedInstanceState != null) { + FragmentManager fm = getSupportFragmentManager(); + mServerFragment = (ServerFragment) fm.getFragment( + savedInstanceState, ServerFragment.class.getName()); + mRouteFragment = (RouteFragment) fm.getFragment( + savedInstanceState, RouteFragment.class.getName()); + mViewPager.setCurrentItem(savedInstanceState.getInt("currentTab")); + } + else { + mServerFragment = new ServerFragment(); + mRouteFragment = new RouteFragment(); + } + onNewIntent(getIntent()); + } + + /** + * Displays the RouteFragment immediately (instead of ServerFragment). + */ @Override protected void onNewIntent(Intent intent) { if (intent.getAction().equals("showRouteFragment")) - mViewPager.setCurrentItem(1); + mViewPager.setCurrentItem(1); } - /** - * 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); - outState.putInt("currentTab", mViewPager.getCurrentItem()); - } - - /** - * Forwards back press to active Fragment (unless the fragment is - * showing its root view). - */ - @Override - public void onBackPressed() { - OnBackPressedListener currentFragment = (OnBackPressedListener) - mSectionsPagerAdapter.getItem(mViewPager.getCurrentItem()); - if (!currentFragment.onBackPressed()) - super.onBackPressed(); - } - - /** - * Changes volume on key press (via RouteFragment). - */ - @Override - public boolean dispatchKeyEvent(KeyEvent event) { - switch (event.getKeyCode()) { - case KeyEvent.KEYCODE_VOLUME_UP: - if (event.getAction() == KeyEvent.ACTION_DOWN) - mRouteFragment.increaseVolume(); - return true; - case KeyEvent.KEYCODE_VOLUME_DOWN: - if (event.getAction() == KeyEvent.ACTION_DOWN) - mRouteFragment.decreaseVolume(); - return true; - default: - return super.dispatchKeyEvent(event); - } - } + /** + * 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); + outState.putInt("currentTab", mViewPager.getCurrentItem()); + } - /** - * Starts playing the playlist from item start (via RouteFragment). - */ + /** + * Forwards back press to active Fragment (unless the fragment is + * showing its root view). + */ + @Override + public void onBackPressed() { + OnBackPressedListener currentFragment = (OnBackPressedListener) + mSectionsPagerAdapter.getItem(mViewPager.getCurrentItem()); + if (!currentFragment.onBackPressed()) + super.onBackPressed(); + } + + /** + * Changes volume on key press (via RouteFragment). + */ + @Override + public boolean dispatchKeyEvent(KeyEvent event) { + switch (event.getKeyCode()) { + case KeyEvent.KEYCODE_VOLUME_UP: + if (event.getAction() == KeyEvent.ACTION_DOWN) + mRouteFragment.increaseVolume(); + return true; + case KeyEvent.KEYCODE_VOLUME_DOWN: + if (event.getAction() == KeyEvent.ACTION_DOWN) + mRouteFragment.decreaseVolume(); + return true; + default: + return super.dispatchKeyEvent(event); + } + } + + /** + * Starts playing the playlist from item start (via RouteFragment). + */ public void play(List playlist, int start) { - mViewPager.setCurrentItem(1); + mViewPager.setCurrentItem(1); mRouteFragment.play(playlist, start); } - + } diff --git a/src/com/github/nutomic/controldlna/gui/RouteFragment.java b/src/com/github/nutomic/controldlna/gui/RouteFragment.java index 6f1dd39..563dfa9 100644 --- a/src/com/github/nutomic/controldlna/gui/RouteFragment.java +++ b/src/com/github/nutomic/controldlna/gui/RouteFragment.java @@ -4,12 +4,12 @@ All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * Neither the name of the nor the + * Neither the name of the nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. @@ -73,18 +73,18 @@ import com.github.nutomic.controldlna.utility.FileArrayAdapter; import com.github.nutomic.controldlna.utility.RouteAdapter; /** - * Controls media playback by showing a list of routes, and after selecting one, + * Controls media playback by showing a list of routes, and after selecting one, * the current playlist and playback controls. * * @author Felix Ableitner * */ -public class RouteFragment extends MediaRouteDiscoveryFragment implements - OnBackPressedListener, OnItemClickListener, OnClickListener, +public class RouteFragment extends MediaRouteDiscoveryFragment implements + OnBackPressedListener, OnItemClickListener, OnClickListener, OnSeekBarChangeListener, OnScrollListener { - + private ListView mListView; - + private View mControls; private SeekBar mProgressBar; private ImageButton mPlayPause; @@ -92,32 +92,32 @@ public class RouteFragment extends MediaRouteDiscoveryFragment implements private ImageButton mRepeat; private TextView mCurrentTimeView; private TextView mTotalTimeView; - + private View mCurrentTrackView; - + private boolean mPlaying; - + private boolean mRestorePlaylistMode; - + private RouteAdapter mRouteAdapter; - + private FileArrayAdapter mPlaylistAdapter; - + private RouteInfo mSelectedRoute; - + /** - * Count of the number of taps on the previous button within the + * Count of the number of taps on the previous button within the * doubletap interval. */ private int mPreviousTapCount = 0; - + /** * If true, the item at this position will be played as soon as a route is selected. */ private int mStartPlayingOnSelect = -1; private MediaRouterPlayServiceBinder mMediaRouterPlayService; - + private ServiceConnection mPlayServiceConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { @@ -128,173 +128,172 @@ public class RouteFragment extends MediaRouteDiscoveryFragment implements applyColors(); if (mRestorePlaylistMode) playlistMode(mMediaRouterPlayService.getService().getCurrentRoute()); - } + } - public void onServiceDisconnected(ComponentName className) { - mMediaRouterPlayService = null; - } - }; - - /** - * Selects remote playback route category. - */ - public RouteFragment() { - MediaRouteSelector mSelector = new MediaRouteSelector.Builder() - .addControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK) - .build(); - setRouteSelector(mSelector); + public void onServiceDisconnected(ComponentName className) { + mMediaRouterPlayService = null; + } + }; + + /** + * Selects remote playback route category. + */ + public RouteFragment() { + MediaRouteSelector mSelector = new MediaRouteSelector.Builder() + .addControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK) + .build(); + setRouteSelector(mSelector); } - + @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - return inflater.inflate(R.layout.route_fragment, null); + return inflater.inflate(R.layout.route_fragment, null); }; - + /** * Initializes views, connects to service, adds default route. */ - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - mRouteAdapter = new RouteAdapter(getActivity()); - mRouteAdapter.add(MediaRouter.getInstance(getActivity()).getRoutes()); - mRouteAdapter.remove(MediaRouter.getInstance(getActivity()).getDefaultRoute()); - mPlaylistAdapter = new FileArrayAdapter(getActivity()); - - mListView = (ListView) getView().findViewById(R.id.listview); - mListView.setAdapter(mRouteAdapter); - mListView.setOnItemClickListener(this); + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + mRouteAdapter = new RouteAdapter(getActivity()); + mRouteAdapter.add(MediaRouter.getInstance(getActivity()).getRoutes()); + mRouteAdapter.remove(MediaRouter.getInstance(getActivity()).getDefaultRoute()); + mPlaylistAdapter = new FileArrayAdapter(getActivity()); + + mListView = (ListView) getView().findViewById(R.id.listview); + mListView.setAdapter(mRouteAdapter); + mListView.setOnItemClickListener(this); mListView.setOnScrollListener(this); mListView.setEmptyView(getView().findViewById(android.R.id.empty)); - - mControls = getView().findViewById(R.id.controls); - mProgressBar = (SeekBar) getView().findViewById(R.id.progressBar); - mProgressBar.setOnSeekBarChangeListener(this); - - mShuffle = (ImageButton) getView().findViewById(R.id.shuffle); - mShuffle.setImageResource(R.drawable.ic_action_shuffle); - mShuffle.setOnClickListener(this); - - ImageButton previous = (ImageButton) getView().findViewById(R.id.previous); - previous.setImageResource(R.drawable.ic_action_previous); - previous.setOnClickListener(this); - - ImageButton next = (ImageButton) getView().findViewById(R.id.next); - next.setImageResource(R.drawable.ic_action_next); - next.setOnClickListener(this); - - mRepeat = (ImageButton) getView().findViewById(R.id.repeat); - mRepeat.setImageResource(R.drawable.ic_action_repeat); - mRepeat.setOnClickListener(this); - - mPlayPause = (ImageButton) getView().findViewById(R.id.playpause); - mPlayPause.setOnClickListener(this); - mPlayPause.setImageResource(R.drawable.ic_action_play); - - mCurrentTimeView = (TextView) getView().findViewById(R.id.current_time); - mTotalTimeView = (TextView) getView().findViewById(R.id.total_time); - getActivity().getApplicationContext().startService( - new Intent(getActivity(), MediaRouterPlayService.class)); - getActivity().getApplicationContext().bindService( - new Intent(getActivity(), MediaRouterPlayService.class), - mPlayServiceConnection, - Context.BIND_AUTO_CREATE - ); - - if (savedInstanceState != null) { - mListView.onRestoreInstanceState(savedInstanceState.getParcelable("list_state")); - mRestorePlaylistMode = savedInstanceState.getBoolean("route_selected"); - } - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - - outState.putBoolean("route_selected", mSelectedRoute != null); - outState.putParcelable("list_state", mListView.onSaveInstanceState()); - } - - @Override - public void onDestroy() { - super.onDestroy(); - getActivity().getApplicationContext().unbindService(mPlayServiceConnection); - } + mControls = getView().findViewById(R.id.controls); + mProgressBar = (SeekBar) getView().findViewById(R.id.progressBar); + mProgressBar.setOnSeekBarChangeListener(this); - /** - * Starts active route discovery (which is automatically stopped on - * fragment stop by parent class). - */ - @Override - public int onPrepareCallbackFlags() { - return MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY - | MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN; - } - - @Override - public Callback onCreateCallback() { - return new MediaRouter.Callback() { - @Override - public void onRouteAdded(MediaRouter router, RouteInfo route) { - for (int i = 0; i < mRouteAdapter.getCount(); i++) { - if (mRouteAdapter.getItem(i).getId().equals(route.getId())) { - mRouteAdapter.remove(mRouteAdapter.getItem(i)); - break; - } - } - mRouteAdapter.add(route); - } + mShuffle = (ImageButton) getView().findViewById(R.id.shuffle); + mShuffle.setImageResource(R.drawable.ic_action_shuffle); + mShuffle.setOnClickListener(this); - @Override - public void onRouteChanged(MediaRouter router, RouteInfo route) { - mRouteAdapter.notifyDataSetChanged(); - } + ImageButton previous = (ImageButton) getView().findViewById(R.id.previous); + previous.setImageResource(R.drawable.ic_action_previous); + previous.setOnClickListener(this); - @Override - public void onRouteRemoved(MediaRouter router, RouteInfo route) { - mRouteAdapter.remove(route); - if (route.equals(mSelectedRoute)) { - mPlaying = false; - onBackPressed(); - } - } + ImageButton next = (ImageButton) getView().findViewById(R.id.next); + next.setImageResource(R.drawable.ic_action_next); + next.setOnClickListener(this); - @Override - public void onRouteSelected(MediaRouter router, RouteInfo route) { - } + mRepeat = (ImageButton) getView().findViewById(R.id.repeat); + mRepeat.setImageResource(R.drawable.ic_action_repeat); + mRepeat.setOnClickListener(this); - @Override - public void onRouteUnselected(MediaRouter router, RouteInfo route) { - } + mPlayPause = (ImageButton) getView().findViewById(R.id.playpause); + mPlayPause.setOnClickListener(this); + mPlayPause.setImageResource(R.drawable.ic_action_play); - @Override - public void onRouteVolumeChanged(MediaRouter router, RouteInfo route) { - } + mCurrentTimeView = (TextView) getView().findViewById(R.id.current_time); + mTotalTimeView = (TextView) getView().findViewById(R.id.total_time); - @Override - public void onRoutePresentationDisplayChanged( - MediaRouter router, RouteInfo route) { - } + getActivity().getApplicationContext().startService( + new Intent(getActivity(), MediaRouterPlayService.class)); + getActivity().getApplicationContext().bindService( + new Intent(getActivity(), MediaRouterPlayService.class), + mPlayServiceConnection, + Context.BIND_AUTO_CREATE + ); - @Override - public void onProviderAdded(MediaRouter router, ProviderInfo provider) { - } + if (savedInstanceState != null) { + mListView.onRestoreInstanceState(savedInstanceState.getParcelable("list_state")); + mRestorePlaylistMode = savedInstanceState.getBoolean("route_selected"); + } + } - @Override - public void onProviderRemoved(MediaRouter router, ProviderInfo provider) { - } + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + + outState.putBoolean("route_selected", mSelectedRoute != null); + outState.putParcelable("list_state", mListView.onSaveInstanceState()); + } + + @Override + public void onDestroy() { + super.onDestroy(); + getActivity().getApplicationContext().unbindService(mPlayServiceConnection); + } + + /** + * Starts active route discovery (which is automatically stopped on + * fragment stop by parent class). + */ + @Override + public int onPrepareCallbackFlags() { + return MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY + | MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN; + } + + @Override + public Callback onCreateCallback() { + return new MediaRouter.Callback() { + @Override + public void onRouteAdded(MediaRouter router, RouteInfo route) { + for (int i = 0; i < mRouteAdapter.getCount(); i++) + if (mRouteAdapter.getItem(i).getId().equals(route.getId())) { + mRouteAdapter.remove(mRouteAdapter.getItem(i)); + break; + } + mRouteAdapter.add(route); + } + + @Override + public void onRouteChanged(MediaRouter router, RouteInfo route) { + mRouteAdapter.notifyDataSetChanged(); + } + + @Override + public void onRouteRemoved(MediaRouter router, RouteInfo route) { + mRouteAdapter.remove(route); + if (route.equals(mSelectedRoute)) { + mPlaying = false; + onBackPressed(); + } + } + + @Override + public void onRouteSelected(MediaRouter router, RouteInfo route) { + } + + @Override + public void onRouteUnselected(MediaRouter router, RouteInfo route) { + } + + @Override + public void onRouteVolumeChanged(MediaRouter router, RouteInfo route) { + } + + @Override + public void onRoutePresentationDisplayChanged( + MediaRouter router, RouteInfo route) { + } + + @Override + public void onProviderAdded(MediaRouter router, ProviderInfo provider) { + } + + @Override + public void onProviderRemoved(MediaRouter router, ProviderInfo provider) { + } + + @Override + public void onProviderChanged(MediaRouter router, ProviderInfo provider) { + } + }; + + } - @Override - public void onProviderChanged(MediaRouter router, ProviderInfo provider) { - } - }; - - } - /** * Selects a route or starts playback (depending on current ListAdapter). */ @@ -307,7 +306,7 @@ public class RouteFragment extends MediaRouteDiscoveryFragment implements changePlayPauseState(true); } } - + /** * Displays UPNP devices in the ListView. */ @@ -319,7 +318,7 @@ public class RouteFragment extends MediaRouteDiscoveryFragment implements TextView emptyView = (TextView) mListView.getEmptyView(); emptyView.setText(R.string.route_list_empty); } - + /** * Displays playlist for route in the ListView. */ @@ -334,25 +333,25 @@ public class RouteFragment extends MediaRouteDiscoveryFragment implements mStartPlayingOnSelect = -1; } TextView emptyView = (TextView) mListView.getEmptyView(); - emptyView.setText(R.string.playlist_empty); + emptyView.setText(R.string.playlist_empty); } - + /** * Sets colored background on the item that is currently playing. */ private void enableTrackHighlight() { if (mListView.getAdapter() == mRouteAdapter || mMediaRouterPlayService == null || !isVisible()) return; - + disableTrackHighlight(); mCurrentTrackView = mListView.getChildAt(mMediaRouterPlayService.getService() .getCurrentTrack() - mListView.getFirstVisiblePosition() + mListView.getHeaderViewsCount()); if (mCurrentTrackView != null) mCurrentTrackView.setBackgroundColor( - getResources().getColor(R.color.currently_playing_background)); + getResources().getColor(R.color.currently_playing_background)); } - + /** * Removes highlight from the item that was last highlighted. */ @@ -367,25 +366,24 @@ public class RouteFragment extends MediaRouteDiscoveryFragment implements @Override public boolean onBackPressed() { if (mListView.getAdapter() == mPlaylistAdapter) { - if (mPlaying) { + if (mPlaying) new AlertDialog.Builder(getActivity()) - .setMessage(R.string.exit_renderer) - .setPositiveButton(android.R.string.yes, - new DialogInterface.OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, - int which) { - mMediaRouterPlayService.getService().stop(); - deviceListMode(); - } - }) - .setNegativeButton(android.R.string.no, null) - .show(); - } + .setMessage(R.string.exit_renderer) + .setPositiveButton(android.R.string.yes, + new DialogInterface.OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, + int which) { + mMediaRouterPlayService.getService().stop(); + deviceListMode(); + } + }) + .setNegativeButton(android.R.string.no, null) + .show(); else deviceListMode(); - return true; + return true; } return false; } @@ -413,24 +411,24 @@ public class RouteFragment extends MediaRouteDiscoveryFragment implements break; case R.id.previous: mPreviousTapCount++; - Handler handler = new Handler(); - Runnable r = new Runnable() { + Handler handler = new Handler(); + Runnable r = new Runnable() { - @Override - public void run() { - // Single tap. - mPreviousTapCount = 0; - s.play(s.getCurrentTrack()); - changePlayPauseState(true); - } - }; - if (mPreviousTapCount == 1) - handler.postDelayed(r, ViewConfiguration.getDoubleTapTimeout()); - else if(mPreviousTapCount == 2) { - // Double tap. - mPreviousTapCount = 0; - s.playPrevious(); - } + @Override + public void run() { + // Single tap. + mPreviousTapCount = 0; + s.play(s.getCurrentTrack()); + changePlayPauseState(true); + } + }; + if (mPreviousTapCount == 1) + handler.postDelayed(r, ViewConfiguration.getDoubleTapTimeout()); + else if(mPreviousTapCount == 2) { + // Double tap. + mPreviousTapCount = 0; + s.playPrevious(); + } break; case R.id.next: boolean stillPlaying = s.playNext(); @@ -440,9 +438,9 @@ public class RouteFragment extends MediaRouteDiscoveryFragment implements s.toggleRepeatEnabled(); applyColors(); break; - } + } } - + /** * Enables or disables highlighting on shuffle/repeat buttons (depending * if they are enabled or disabled). @@ -451,20 +449,20 @@ public class RouteFragment extends MediaRouteDiscoveryFragment implements MediaRouterPlayService s = mMediaRouterPlayService.getService(); int highlight = getResources().getColor(R.color.button_highlight); int transparent = getResources().getColor(android.R.color.transparent); - - mShuffle.setColorFilter((s.getShuffleEnabled()) + + mShuffle.setColorFilter((s.getShuffleEnabled()) ? highlight - : transparent); - mRepeat.setColorFilter((s.getRepeatEnabled()) + : transparent); + mRepeat.setColorFilter((s.getRepeatEnabled()) ? highlight - : transparent); + : transparent); } /** * Sends manual seek on progress bar to renderer. */ @Override - public void onProgressChanged(SeekBar seekBar, int progress, + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { if (fromUser) mMediaRouterPlayService.getService().seek(progress); @@ -490,11 +488,11 @@ public class RouteFragment extends MediaRouteDiscoveryFragment implements public void onScrollStateChanged(AbsListView arg0, int arg1) { enableTrackHighlight(); } - + public void increaseVolume() { mMediaRouterPlayService.getService().increaseVolume(); } - + public void decreaseVolume() { mMediaRouterPlayService.getService().decreaseVolume(); } @@ -506,13 +504,13 @@ public class RouteFragment extends MediaRouteDiscoveryFragment implements mPlaylistAdapter.clear(); mPlaylistAdapter.add(playlist); mMediaRouterPlayService.getService().setPlaylist(playlist); - + if (mSelectedRoute != null) { mMediaRouterPlayService.getService().play(start); changePlayPauseState(true); } else { Toast.makeText(getActivity(), R.string.select_route, Toast.LENGTH_SHORT) - .show(); + .show(); mStartPlayingOnSelect = start; } } @@ -525,17 +523,17 @@ public class RouteFragment extends MediaRouteDiscoveryFragment implements */ private String generateTimeString(int time) { assert(time >= 0); - int seconds = (int) time % 60; - int minutes = (int) time / 60; + int seconds = time % 60; + int minutes = time / 60; if (minutes > 99) return "99:99"; else - return Integer.toString(minutes) + ":" + - ((seconds > 9) - ? seconds + return Integer.toString(minutes) + ":" + + ((seconds > 9) + ? seconds : "0" + Integer.toString(seconds)); } - + /** * Sent by MediaRouterPlayService when playback of a new track is started. * @@ -544,7 +542,7 @@ public class RouteFragment extends MediaRouteDiscoveryFragment implements public void receiveIsPlaying(int track) { mListView.smoothScrollToPosition(track); } - + /** * Receives information from MediaRouterPlayService about playback status. */ @@ -552,13 +550,13 @@ public class RouteFragment extends MediaRouteDiscoveryFragment implements // Views may not exist if fragment was just created/destroyed. if (getView() == null) return; - + int currentTime = (int) status.getContentPosition() / 1000; int totalTime = (int) status.getContentDuration() / 1000; - + mCurrentTimeView.setText(generateTimeString(currentTime)); mTotalTimeView.setText(generateTimeString(totalTime)); - + mProgressBar.setProgress(currentTime); mProgressBar.setMax(totalTime); @@ -568,13 +566,13 @@ public class RouteFragment extends MediaRouteDiscoveryFragment implements changePlayPauseState(true); else changePlayPauseState(false); - - if (mListView.getAdapter() == mPlaylistAdapter) + + if (mListView.getAdapter() == mPlaylistAdapter) enableTrackHighlight(); } - + /** - * Changes the state of mPlayPause button to pause/resume according to + * Changes the state of mPlayPause button to pause/resume according to * current playback state, also sets mPlaying. * * @param playing True if an item is currently being played, false otherwise. @@ -587,7 +585,7 @@ public class RouteFragment extends MediaRouteDiscoveryFragment implements } else { mPlayPause.setImageResource(R.drawable.ic_action_play); - mPlayPause.setContentDescription(getResources().getString(R.string.play)); + mPlayPause.setContentDescription(getResources().getString(R.string.play)); } } diff --git a/src/com/github/nutomic/controldlna/gui/ServerFragment.java b/src/com/github/nutomic/controldlna/gui/ServerFragment.java index fbe554e..96db53f 100644 --- a/src/com/github/nutomic/controldlna/gui/ServerFragment.java +++ b/src/com/github/nutomic/controldlna/gui/ServerFragment.java @@ -4,12 +4,12 @@ All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * Neither the name of the nor the + * Neither the name of the nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. @@ -75,293 +75,290 @@ import com.github.nutomic.controldlna.utility.FileArrayAdapter; * directories. * * @author Felix Ableitner - * + * */ public class ServerFragment extends ListFragment implements OnBackPressedListener { - + private final static String TAG = "ServerFragment"; - + private final static String ROOT_DIRECTORY = "0"; - + /** * ListView adapter for showing a list of DLNA media servers. */ 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. */ private Device mCurrentServer; - + private String mRestoreServer; - + /** * ListView adapter for showing a list of files/folders. */ 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. */ private Stack mCurrentPath = new Stack(); - + /** * Holds the scroll position in the list view at each directory level. */ private Stack mListState = new Stack(); - - protected AndroidUpnpService mUpnpService; - private ServiceConnection mUpnpServiceConnection = new ServiceConnection() { + protected AndroidUpnpService mUpnpService; - /** - * Registers DeviceListener, adds known devices and starts search if requested. - */ + private ServiceConnection mUpnpServiceConnection = new ServiceConnection() { + + /** + * Registers DeviceListener, adds known devices and starts search if requested. + */ public void onServiceConnected(ComponentName className, IBinder service) { - mUpnpService = (AndroidUpnpService) service; - mUpnpService.getRegistry().addListener(mServerAdapter); - for (Device d : mUpnpService.getControlPoint().getRegistry().getDevices()) - mServerAdapter.deviceAdded(d); - mUpnpService.getControlPoint().search(); - - if (mRestoreServer != null) { - mCurrentServer = mUpnpService.getControlPoint().getRegistry() - .getDevice(new UDN(mRestoreServer.replace("uuid:", "")), false); - if (mCurrentServer != null) { - setListAdapter(mFileAdapter); - // Duplicate the top element because getFiles will remove it. - mListState.add(mListState.peek()); - getFiles(true); - } + mUpnpService = (AndroidUpnpService) service; + mUpnpService.getRegistry().addListener(mServerAdapter); + for (Device d : mUpnpService.getControlPoint().getRegistry().getDevices()) + mServerAdapter.deviceAdded(d); + mUpnpService.getControlPoint().search(); - getListView().onRestoreInstanceState(mListState.peek()); - } - } + if (mRestoreServer != null) { + mCurrentServer = mUpnpService.getControlPoint().getRegistry() + .getDevice(new UDN(mRestoreServer.replace("uuid:", "")), false); + if (mCurrentServer != null) { + setListAdapter(mFileAdapter); + // Duplicate the top element because getFiles will remove it. + mListState.add(mListState.peek()); + getFiles(true); + } + + getListView().onRestoreInstanceState(mListState.peek()); + } + } + + public void onServiceDisconnected(ComponentName className) { + mUpnpService = null; + } + }; - public void onServiceDisconnected(ComponentName className) { - mUpnpService = null; - } - }; - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - return inflater.inflate(R.layout.server_fragment, null); + return inflater.inflate(R.layout.server_fragment, null); }; - + /** - * Initializes ListView adapters, launches Cling UPNP service, registers + * Initializes ListView adapters, launches Cling UPNP service, registers * wifi state change listener and restores instance state if possible. */ - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - mFileAdapter = new FileArrayAdapter(getActivity()); + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + mFileAdapter = new FileArrayAdapter(getActivity()); - mServerAdapter = new DeviceArrayAdapter( - getActivity(), DeviceArrayAdapter.SERVER); - setListAdapter(mServerAdapter); - getActivity().getApplicationContext().bindService( - new Intent(getActivity(), AndroidUpnpServiceImpl.class), - mUpnpServiceConnection, - Context.BIND_AUTO_CREATE - ); - - IntentFilter filter = new IntentFilter(); - filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); - filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); - getActivity().registerReceiver(mWifiReceiver, filter); - - if (savedInstanceState != null) { - mRestoreServer = savedInstanceState.getString("current_server"); - mCurrentPath.addAll(savedInstanceState.getStringArrayList("path")); - mListState.addAll(savedInstanceState.getParcelableArrayList("list_state")); - } else - mListState.push(getListView().onSaveInstanceState()); - } - - /** - * Stores current server and path/list state stacks. - */ - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - outState.putString("current_server", (mCurrentServer != null) - ? mCurrentServer.getIdentity().getUdn().toString() - : ""); - outState.putStringArrayList("path", new ArrayList(mCurrentPath)); - mListState.pop(); - mListState.push(getListView().onSaveInstanceState()); - outState.putParcelableArrayList("list_state", new ArrayList(mListState)); - } - - @Override - public void onDestroy() { - super.onDestroy(); - getActivity().getApplicationContext().unbindService(mUpnpServiceConnection); - getActivity().unregisterReceiver(mWifiReceiver); - } - - /** - * Enters directory browsing mode or enters a deeper level directory. - */ - @Override - public void onListItemClick(ListView l, View v, int position, long id) { - if (getListAdapter() == mServerAdapter) - browsingMode(mServerAdapter.getItem(position)); - else if (getListAdapter() == mFileAdapter) { - if (mFileAdapter.getItem(position) instanceof Container) - getFiles(((Container) mFileAdapter.getItem(position)).getId()); - else { - List playlist = new ArrayList(); - for (int i = 0; i < mFileAdapter.getCount(); i++) { - if (mFileAdapter.getItem(i) instanceof Item) - playlist.add((Item) mFileAdapter.getItem(i)); - } - MainActivity activity = (MainActivity) getActivity(); - activity.play(playlist, position); - } - } - } + mServerAdapter = new DeviceArrayAdapter( + getActivity(), DeviceArrayAdapter.SERVER); + setListAdapter(mServerAdapter); + getActivity().getApplicationContext().bindService( + new Intent(getActivity(), AndroidUpnpServiceImpl.class), + mUpnpServiceConnection, + Context.BIND_AUTO_CREATE + ); - /** - * Displays available servers in the ListView. - */ - private void serverMode() { + IntentFilter filter = new IntentFilter(); + filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); + filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); + getActivity().registerReceiver(mWifiReceiver, filter); + + if (savedInstanceState != null) { + mRestoreServer = savedInstanceState.getString("current_server"); + mCurrentPath.addAll(savedInstanceState.getStringArrayList("path")); + mListState.addAll(savedInstanceState.getParcelableArrayList("list_state")); + } else + mListState.push(getListView().onSaveInstanceState()); + } + + /** + * Stores current server and path/list state stacks. + */ + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putString("current_server", (mCurrentServer != null) + ? mCurrentServer.getIdentity().getUdn().toString() + : ""); + outState.putStringArrayList("path", new ArrayList(mCurrentPath)); + mListState.pop(); + mListState.push(getListView().onSaveInstanceState()); + outState.putParcelableArrayList("list_state", new ArrayList(mListState)); + } + + @Override + public void onDestroy() { + super.onDestroy(); + getActivity().getApplicationContext().unbindService(mUpnpServiceConnection); + getActivity().unregisterReceiver(mWifiReceiver); + } + + /** + * Enters directory browsing mode or enters a deeper level directory. + */ + @Override + public void onListItemClick(ListView l, View v, int position, long id) { + if (getListAdapter() == mServerAdapter) + browsingMode(mServerAdapter.getItem(position)); + else if (getListAdapter() == mFileAdapter) + if (mFileAdapter.getItem(position) instanceof Container) + getFiles(((Container) mFileAdapter.getItem(position)).getId()); + else { + List playlist = new ArrayList(); + for (int i = 0; i < mFileAdapter.getCount(); i++) + if (mFileAdapter.getItem(i) instanceof Item) + playlist.add((Item) mFileAdapter.getItem(i)); + MainActivity activity = (MainActivity) getActivity(); + activity.play(playlist, position); + } + } + + /** + * Displays available servers in the ListView. + */ + private void serverMode() { setListAdapter(mServerAdapter); mCurrentServer = null; TextView emptyView = (TextView) getListView().getEmptyView(); - emptyView.setText(R.string.device_list_empty); + emptyView.setText(R.string.device_list_empty); getListView().onRestoreInstanceState(mListState.pop()); - } - - /** - * Displays files for server (starting from root). - */ - private void browsingMode(Device server) { + } + + /** + * Displays files for server (starting from root). + */ + private void browsingMode(Device server) { setListAdapter(mFileAdapter); mCurrentServer = server; getFiles(ROOT_DIRECTORY); TextView emptyView = (TextView) getListView().getEmptyView(); - emptyView.setText(R.string.folder_list_empty); - } - /** - * Opens a new directory and displays it. - */ - private void getFiles(String directory) { - mListState.push(getListView().onSaveInstanceState()); - mCurrentPath.push(directory); - getFiles(false); - } - - /** - * Displays the current directory on the ListView. - * - * @param restoreListState True if we are going back up the directory tree, - * which means we restore scroll position etc. This pops - * mListState. - */ - private void getFiles(final boolean restoreListState) { - if (mCurrentServer == null) - return; - - Service service = mCurrentServer.findService( - new ServiceType("schemas-upnp-org", "ContentDirectory")); - mUpnpService.getControlPoint().execute(new Browse(service, + emptyView.setText(R.string.folder_list_empty); + } + + /** + * Opens a new directory and displays it. + */ + private void getFiles(String directory) { + mListState.push(getListView().onSaveInstanceState()); + mCurrentPath.push(directory); + getFiles(false); + } + + /** + * Displays the current directory on the ListView. + * + * @param restoreListState True if we are going back up the directory tree, + * which means we restore scroll position etc. This pops + * mListState. + */ + private void getFiles(final boolean restoreListState) { + if (mCurrentServer == null) + return; + + Service service = mCurrentServer.findService( + new ServiceType("schemas-upnp-org", "ContentDirectory")); + mUpnpService.getControlPoint().execute(new Browse(service, mCurrentPath.peek(), BrowseFlag.DIRECT_CHILDREN) { - - @SuppressWarnings("rawtypes") + + @SuppressWarnings("rawtypes") + @Override + public void received(ActionInvocation actionInvocation, + final DIDLContent didl) { + getActivity().runOnUiThread(new Runnable() { + @Override - public void received(ActionInvocation actionInvocation, - final DIDLContent didl) { - getActivity().runOnUiThread(new Runnable() { - - @Override - public void run() { - mFileAdapter.clear(); - for (Container c : didl.getContainers()) - mFileAdapter.add(c); - for (Item i : didl.getItems()) - mFileAdapter.add(i); - if (restoreListState) - getListView().onRestoreInstanceState(mListState.pop()); - else - getListView().setSelectionFromTop(0, 0); - } - }); + public void run() { + mFileAdapter.clear(); + for (Container c : didl.getContainers()) + mFileAdapter.add(c); + for (Item i : didl.getItems()) + mFileAdapter.add(i); + if (restoreListState) + getListView().onRestoreInstanceState(mListState.pop()); + else + getListView().setSelectionFromTop(0, 0); } - - @Override - public void updateStatus(Status status) { - } - - @SuppressWarnings("rawtypes") - @Override - public void failure(ActionInvocation actionInvocation, - UpnpResponse operation, String defaultMessage) { - Log.w(TAG, "Failed to load directory contents: " + - defaultMessage); - } - - }); - } - - /** - * Handles back button press to traverse directories (while browsing - * directories). - */ + }); + } + + @Override + public void updateStatus(Status status) { + } + + @SuppressWarnings("rawtypes") + @Override + public void failure(ActionInvocation actionInvocation, + UpnpResponse operation, String defaultMessage) { + Log.w(TAG, "Failed to load directory contents: " + + defaultMessage); + } + + }); + } + + /** + * Handles back button press to traverse directories (while browsing + * directories). + */ public boolean onBackPressed() { - if (getListAdapter() == mServerAdapter) - return false; - + if (getListAdapter() == mServerAdapter) + return false; + mCurrentPath.pop(); if (mCurrentPath.empty()) serverMode(); else getFiles(true); - return true; + return true; } - + /** - * Starts device search on wifi connect, removes unreachable + * Starts device search on wifi connect, removes unreachable * devices on wifi disconnect. */ private BroadcastReceiver mWifiReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - getActivity(); - ConnectivityManager connManager = (ConnectivityManager) - getActivity().getSystemService(Context.CONNECTIVITY_SERVICE); - NetworkInfo wifi = connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI); - - if (wifi.isConnected()) { - if (mUpnpService != null) { - for (Device d : mUpnpService.getControlPoint() - .getRegistry().getDevices()) - mServerAdapter.deviceAdded(d); - mUpnpService.getControlPoint().search(); - } - } - else { - for (int i = 0; i < mServerAdapter.getCount(); i++) { - Device d = mServerAdapter.getItem(i); - UDN udn = new UDN(d.getIdentity().getUdn().toString()); - if (mUpnpService.getControlPoint().getRegistry() - .getDevice(udn, false) == null) { - mServerAdapter.deviceRemoved(d); - if (d.equals(mCurrentServer)) { - mListState.setSize(2); - mCurrentPath.clear(); - serverMode(); - } - } - } - } - } + @Override + public void onReceive(Context context, Intent intent) { + getActivity(); + ConnectivityManager connManager = (ConnectivityManager) + getActivity().getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo wifi = connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI); + + if (wifi.isConnected()) { + if (mUpnpService != null) { + for (Device d : mUpnpService.getControlPoint() + .getRegistry().getDevices()) + mServerAdapter.deviceAdded(d); + mUpnpService.getControlPoint().search(); + } + } else + for (int i = 0; i < mServerAdapter.getCount(); i++) { + Device d = mServerAdapter.getItem(i); + UDN udn = new UDN(d.getIdentity().getUdn().toString()); + if (mUpnpService.getControlPoint().getRegistry() + .getDevice(udn, false) == null) { + mServerAdapter.deviceRemoved(d); + if (d.equals(mCurrentServer)) { + mListState.setSize(2); + mCurrentPath.clear(); + serverMode(); + } + } + } + } }; } diff --git a/src/com/github/nutomic/controldlna/mediarouter/MediaRouterPlayService.java b/src/com/github/nutomic/controldlna/mediarouter/MediaRouterPlayService.java index 10a6171..6708b3b 100644 --- a/src/com/github/nutomic/controldlna/mediarouter/MediaRouterPlayService.java +++ b/src/com/github/nutomic/controldlna/mediarouter/MediaRouterPlayService.java @@ -4,12 +4,12 @@ All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * Neither the name of the nor the + * Neither the name of the nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. @@ -70,61 +70,61 @@ import com.github.nutomic.controldlna.utility.LoadImageTask; public class MediaRouterPlayService extends Service { private static final String TAG = "PlayService"; - + private static final int NOTIFICATION_ID = 1; - + private final MediaRouterPlayServiceBinder mBinder = new MediaRouterPlayServiceBinder(this); - + private MediaRouter mMediaRouter; - + /** * Media items that should be played. */ private List mPlaylist = new ArrayList(); - + /** * The track that is currently being played. */ private int mCurrentTrack = -1; - + private boolean mShuffle = false; - + private boolean mRepeat = false; - + private String mItemId; - + private String mSessionId; - - private WeakReference mRouterFragment = + + private WeakReference mRouterFragment = new WeakReference(null); - + private boolean mPollingStatus = false; - + private boolean mBound; - + /** * Route that is currently being played to. May be invalid. */ private RouteInfo mCurrentRoute; - + /* - * Stops foreground mode and notification if the current route + * Stops foreground mode and notification if the current route * has been removed. */ - private MediaRouter.Callback mRouteRemovedCallback = + private MediaRouter.Callback mRouteRemovedCallback = new MediaRouter.Callback() { @Override public void onRouteRemoved(MediaRouter router, RouteInfo route) { if (route.equals(mCurrentRoute)) stopForeground(true); } -}; - + }; + /** * Creates a notification after the icon bitmap is loaded. */ private class CreateNotificationTask extends LoadImageTask { - + @Override protected void onPostExecute(Bitmap result) { String title = ""; @@ -132,16 +132,16 @@ public class MediaRouterPlayService extends Service { if (mCurrentTrack < mPlaylist.size()) { title = mPlaylist.get(mCurrentTrack).getTitle(); if (mPlaylist.get(mCurrentTrack) instanceof MusicTrack) { - MusicTrack track = (MusicTrack) mPlaylist.get(mCurrentTrack); - if (track.getArtists().length > 0) - artist = track.getArtists()[0].getName(); + MusicTrack track = (MusicTrack) mPlaylist.get(mCurrentTrack); + if (track.getArtists().length > 0) + artist = track.getArtists()[0].getName(); } } Intent intent = new Intent(MediaRouterPlayService.this, MainActivity.class); intent.setAction("showRouteFragment"); Notification notification = new NotificationCompat.Builder(MediaRouterPlayService.this) - .setContentIntent(PendingIntent.getActivity(MediaRouterPlayService.this, 0, - intent, 0)) + .setContentIntent(PendingIntent.getActivity(MediaRouterPlayService.this, 0, + intent, 0)) .setContentTitle(title) .setContentText(artist) .setLargeIcon(result) @@ -150,68 +150,68 @@ public class MediaRouterPlayService extends Service { notification.flags |= Notification.FLAG_ONGOING_EVENT; startForeground(NOTIFICATION_ID, notification); } - + } @Override public void onCreate() { super.onCreate(); - mMediaRouter = MediaRouter.getInstance(this); + mMediaRouter = MediaRouter.getInstance(this); pollStatus(); } - + @Override public IBinder onBind(Intent intent) { mBound = true; return mBinder; } - + /** - * Stops service after a delay if no media is playing (delay in case the + * 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) { + public boolean onUnbind(Intent intent) { new Handler().postDelayed(new Runnable() { public void run() { - if (!mPollingStatus && !mBound) + if (!mPollingStatus && !mBound) stopSelf(); - } + } }, 5000); mBound = false; return super.onUnbind(intent); } - + public void setRouterFragment(RouteFragment rf) { mRouterFragment = new WeakReference(rf); } - + public void selectRoute(RouteInfo route) { mMediaRouter.removeCallback(mRouteRemovedCallback); mMediaRouter.selectRoute(route); - MediaRouteSelector selector = new MediaRouteSelector.Builder() - .addControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK) - .build(); + MediaRouteSelector selector = new MediaRouteSelector.Builder() + .addControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK) + .build(); - mMediaRouter.addCallback(selector, mRouteRemovedCallback, 0); - mCurrentRoute = route; + mMediaRouter.addCallback(selector, mRouteRemovedCallback, 0); + mCurrentRoute = route; } - + public void sendControlRequest(Intent intent) { mMediaRouter.getSelectedRoute().sendControlRequest(intent, null); } - + /** - * Sets current track in renderer to specified item in playlist, then + * Sets current track in renderer to specified item in playlist, then * starts playback. */ - public void play(int trackNumber) { + public void play(int trackNumber) { if (trackNumber < 0 || trackNumber >= mPlaylist.size()) return; - + mCurrentTrack = trackNumber; Item track = mPlaylist.get(trackNumber); - DIDLParser parser = new DIDLParser(); + DIDLParser parser = new DIDLParser(); DIDLContent didl = new DIDLContent(); didl.addItem(track); String metadata = ""; @@ -221,88 +221,88 @@ public class MediaRouterPlayService extends Service { catch (Exception e) { Log.w(TAG, "Metadata generation failed", e); } - - Intent intent = new Intent(MediaControlIntent.ACTION_PLAY); - intent.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK); - intent.setData(Uri.parse(track.getFirstResource().getValue())); - intent.putExtra(MediaControlIntent.EXTRA_ITEM_METADATA, metadata); - - mMediaRouter.getSelectedRoute().sendControlRequest(intent, - new ControlRequestCallback() { - @Override - public void onResult(Bundle data) { - mSessionId = data.getString(MediaControlIntent.EXTRA_SESSION_ID); - mItemId = data.getString(MediaControlIntent.EXTRA_ITEM_ID); - mPollingStatus = true; - - new CreateNotificationTask().execute(mPlaylist.get(mCurrentTrack) - .getFirstPropertyValue(DIDLObject.Property.UPNP.ALBUM_ART_URI.class)); - if (mRouterFragment.get() != null) - mRouterFragment.get().receiveIsPlaying(mCurrentTrack); - } - }); + Intent intent = new Intent(MediaControlIntent.ACTION_PLAY); + intent.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK); + intent.setData(Uri.parse(track.getFirstResource().getValue())); + intent.putExtra(MediaControlIntent.EXTRA_ITEM_METADATA, metadata); + + mMediaRouter.getSelectedRoute().sendControlRequest(intent, + new ControlRequestCallback() { + @Override + public void onResult(Bundle data) { + mSessionId = data.getString(MediaControlIntent.EXTRA_SESSION_ID); + mItemId = data.getString(MediaControlIntent.EXTRA_ITEM_ID); + mPollingStatus = true; + + new CreateNotificationTask().execute(mPlaylist.get(mCurrentTrack) + .getFirstPropertyValue(DIDLObject.Property.UPNP.ALBUM_ART_URI.class)); + + if (mRouterFragment.get() != null) + mRouterFragment.get().receiveIsPlaying(mCurrentTrack); + } + }); } - + /** * Sends 'pause' signal to current renderer. */ public void pause() { if (mPlaylist.isEmpty()) return; - - Intent intent = new Intent(MediaControlIntent.ACTION_PAUSE); - intent.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK); + + Intent intent = new Intent(MediaControlIntent.ACTION_PAUSE); + intent.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK); intent.putExtra(MediaControlIntent.EXTRA_SESSION_ID, mSessionId); - mMediaRouter.getSelectedRoute().sendControlRequest(intent, null); - mPollingStatus = false; - stopForeground(true); + mMediaRouter.getSelectedRoute().sendControlRequest(intent, null); + mPollingStatus = false; + stopForeground(true); } - + /** * Sends 'resume' signal to current renderer. */ public void resume() { if (mPlaylist.isEmpty()) return; - - Intent intent = new Intent(MediaControlIntent.ACTION_RESUME); - intent.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK); + + Intent intent = new Intent(MediaControlIntent.ACTION_RESUME); + intent.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK); intent.putExtra(MediaControlIntent.EXTRA_SESSION_ID, mSessionId); - mMediaRouter.getSelectedRoute().sendControlRequest(intent, null); - mPollingStatus = true; - new CreateNotificationTask().execute(mPlaylist.get(mCurrentTrack) - .getFirstPropertyValue(DIDLObject.Property.UPNP.ALBUM_ART_URI.class)); + mMediaRouter.getSelectedRoute().sendControlRequest(intent, null); + mPollingStatus = true; + new CreateNotificationTask().execute(mPlaylist.get(mCurrentTrack) + .getFirstPropertyValue(DIDLObject.Property.UPNP.ALBUM_ART_URI.class)); } - + /** * Sends 'stop' signal to current renderer. */ public void stop() { if (mPlaylist.isEmpty()) return; - - Intent intent = new Intent(MediaControlIntent.ACTION_STOP); - intent.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK); + + Intent intent = new Intent(MediaControlIntent.ACTION_STOP); + intent.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK); intent.putExtra(MediaControlIntent.EXTRA_SESSION_ID, mSessionId); - mMediaRouter.getSelectedRoute().sendControlRequest(intent, null); - mPollingStatus = false; - stopForeground(true); + mMediaRouter.getSelectedRoute().sendControlRequest(intent, null); + mPollingStatus = false; + stopForeground(true); } - + public void seek(int seconds) { if (mPlaylist.isEmpty()) return; - - Intent intent = new Intent(MediaControlIntent.ACTION_SEEK); - intent.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK); + + Intent intent = new Intent(MediaControlIntent.ACTION_SEEK); + intent.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK); intent.putExtra(MediaControlIntent.EXTRA_SESSION_ID, mSessionId); intent.putExtra(MediaControlIntent.EXTRA_ITEM_ID, mItemId); - intent.putExtra(MediaControlIntent.EXTRA_ITEM_CONTENT_POSITION, + intent.putExtra(MediaControlIntent.EXTRA_ITEM_CONTENT_POSITION, (long) seconds * 1000); - mMediaRouter.getSelectedRoute().sendControlRequest(intent, null); + mMediaRouter.getSelectedRoute().sendControlRequest(intent, null); } - + /** * Sets a new playlist and starts playing. * @@ -311,17 +311,17 @@ public class MediaRouterPlayService extends Service { public void setPlaylist(List playlist) { mPlaylist = playlist; } - + /** * Plays the track after current in the playlist. * - * @return True if another item is played, false if the end + * @return True if another item is played, false if the end * of the playlist is reached. */ public boolean playNext() { - if (mCurrentTrack == -1) + if (mCurrentTrack == -1) return false; - + if (mShuffle) { // Play random item. play(new Random().nextInt(mPlaylist.size())); @@ -346,21 +346,21 @@ public class MediaRouterPlayService extends Service { } } - + /** * Plays the track before current in the playlist. */ public void playPrevious() { if (mCurrentTrack == -1) return; - + if (mShuffle) // Play random item. play(new Random().nextInt(mPlaylist.size())); else play(mCurrentTrack - 1); } - + /** * Returns index of the track that is currently played (zero-based). * @return @@ -368,7 +368,7 @@ public class MediaRouterPlayService extends Service { public int getCurrentTrack() { return mCurrentTrack; } - + /** * Requests playback information every second, as long as RendererFragment * is attached or media is playing. @@ -379,60 +379,60 @@ public class MediaRouterPlayService extends Service { i.setAction(MediaControlIntent.ACTION_GET_STATUS); i.putExtra(MediaControlIntent.EXTRA_SESSION_ID, mSessionId); i.putExtra(MediaControlIntent.EXTRA_ITEM_ID, mItemId); - mMediaRouter.getSelectedRoute().sendControlRequest(i, + mMediaRouter.getSelectedRoute().sendControlRequest(i, new ControlRequestCallback() { - @Override - public void onResult(Bundle data) { - MediaItemStatus status = MediaItemStatus.fromBundle(data); - if (status == null) - return; - - if (mRouterFragment.get() != null) - mRouterFragment.get().receivePlaybackStatus(status); - if (status.getPlaybackState() != MediaItemStatus.PLAYBACK_STATE_PENDING && - status.getPlaybackState() != MediaItemStatus.PLAYBACK_STATE_BUFFERING && - status.getPlaybackState() != MediaItemStatus.PLAYBACK_STATE_PLAYING) - stopForeground(true); - - if (status.getPlaybackState() == MediaItemStatus.PLAYBACK_STATE_FINISHED) - playNext(); - } - }); + @Override + public void onResult(Bundle data) { + MediaItemStatus status = MediaItemStatus.fromBundle(data); + if (status == null) + return; + + if (mRouterFragment.get() != null) + mRouterFragment.get().receivePlaybackStatus(status); + if (status.getPlaybackState() != MediaItemStatus.PLAYBACK_STATE_PENDING && + status.getPlaybackState() != MediaItemStatus.PLAYBACK_STATE_BUFFERING && + status.getPlaybackState() != MediaItemStatus.PLAYBACK_STATE_PLAYING) + stopForeground(true); + + if (status.getPlaybackState() == MediaItemStatus.PLAYBACK_STATE_FINISHED) + playNext(); + } + }); } - + new Handler().postDelayed(new Runnable() { - + @Override public void run() { pollStatus(); - } + } }, 1000); - } - + } + public void increaseVolume() { - mMediaRouter.getSelectedRoute().requestUpdateVolume(1); + mMediaRouter.getSelectedRoute().requestUpdateVolume(1); } - + public void decreaseVolume() { - mMediaRouter.getSelectedRoute().requestUpdateVolume(-1); + mMediaRouter.getSelectedRoute().requestUpdateVolume(-1); } - + public List getPlaylist() { return mPlaylist; } - + public void toggleShuffleEnabled() { mShuffle = !mShuffle; } - + public boolean getShuffleEnabled() { return mShuffle; } - + public void toggleRepeatEnabled() { mRepeat = !mRepeat; } - + public boolean getRepeatEnabled() { return mRepeat; } @@ -440,4 +440,5 @@ public class MediaRouterPlayService extends Service { public RouteInfo getCurrentRoute() { return mCurrentRoute; } + } diff --git a/src/com/github/nutomic/controldlna/mediarouter/MediaRouterPlayServiceBinder.java b/src/com/github/nutomic/controldlna/mediarouter/MediaRouterPlayServiceBinder.java index eec2222..4e98dbb 100644 --- a/src/com/github/nutomic/controldlna/mediarouter/MediaRouterPlayServiceBinder.java +++ b/src/com/github/nutomic/controldlna/mediarouter/MediaRouterPlayServiceBinder.java @@ -4,12 +4,12 @@ All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * Neither the name of the nor the + * Neither the name of the nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. @@ -36,14 +36,15 @@ import android.os.Binder; * */ public class MediaRouterPlayServiceBinder extends Binder { - + MediaRouterPlayService mService; - + public MediaRouterPlayServiceBinder(MediaRouterPlayService service) { mService = service; } - + public MediaRouterPlayService getService() { - return mService; - } + return mService; + } + } diff --git a/src/com/github/nutomic/controldlna/upnp/Provider.java b/src/com/github/nutomic/controldlna/upnp/Provider.java index feae9fb..4a37bad 100644 --- a/src/com/github/nutomic/controldlna/upnp/Provider.java +++ b/src/com/github/nutomic/controldlna/upnp/Provider.java @@ -4,12 +4,12 @@ All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * Neither the name of the nor the + * Neither the name of the nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. @@ -66,51 +66,54 @@ import com.github.nutomic.controldlna.R; * @author Felix Ableitner */ final class Provider extends MediaRouteProvider { - + // Device has been added. // param: Device device - public static final int MSG_RENDERER_ADDED = 1; + public static final int MSG_RENDERER_ADDED = 1; + // Device has been removed. // param: int id public static final int MSG_RENDERER_REMOVED = 2; + // Playback status information, retrieved after RemotePlayService.MSG_GET_STATUS. // param: bundle media_item_status // param: int hash public static final int MSG_STATUS_INFO = 3; + // Indicates an error in communication between RemotePlayService and renderer. // param: String error public static final int MSG_ERROR = 4; - + /** * Allows passing and storing basic information about a device. */ static public class Device implements Parcelable { - + public String id; public String name; public String description; public int volume; public int volumeMax; - - public static final Parcelable.Creator CREATOR - = new Parcelable.Creator() { - public Device createFromParcel(Parcel in) { - return new Device(in); - } - public Device[] newArray(int size) { - return new Device[size]; - } - }; - + public static final Parcelable.Creator CREATOR + = new Parcelable.Creator() { + public Device createFromParcel(Parcel in) { + return new Device(in); + } + + public Device[] newArray(int size) { + return new Device[size]; + } + }; + private Device(Parcel in) { - id = in.readString(); - name = in.readString(); - description = in.readString(); - volume = in.readInt(); - volumeMax = in.readInt(); - } - + id = in.readString(); + name = in.readString(); + description = in.readString(); + volume = in.readInt(); + volumeMax = in.readInt(); + } + public Device(String id, String name, String description, int volume, int volumeMax) { this.id = id; this.name = name; @@ -131,271 +134,271 @@ final class Provider extends MediaRouteProvider { dest.writeString(description); dest.writeInt(volume); dest.writeInt(volumeMax); - } - + } + } - - private HashMap mDevices = new HashMap(); - - private SparseArray> mRequests = - new SparseArray>(); - - IRemotePlayService mIRemotePlayService; - - private ServiceConnection mConnection = new ServiceConnection() { - public void onServiceConnected(ComponentName className, IBinder service) { - mIRemotePlayService = IRemotePlayService.Stub.asInterface(service); - } - public void onServiceDisconnected(ComponentName className) { - mIRemotePlayService = null; - } - }; + private HashMap mDevices = new HashMap(); - private static final ArrayList CONTROL_FILTERS; - static { - IntentFilter f = new IntentFilter(); - f.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK); - f.addAction(MediaControlIntent.ACTION_PLAY); - f.addAction(MediaControlIntent.ACTION_PAUSE); - f.addAction(MediaControlIntent.ACTION_SEEK); - f.addAction(MediaControlIntent.ACTION_STOP); - f.addDataScheme("http"); - f.addDataScheme("https"); - try { - f.addDataType("video/*"); - f.addDataType("audio/*"); - } catch (MalformedMimeTypeException ex) { - throw new RuntimeException(ex); - } + private SparseArray> mRequests = + new SparseArray>(); + + IRemotePlayService mIRemotePlayService; + + private ServiceConnection mConnection = new ServiceConnection() { + public void onServiceConnected(ComponentName className, IBinder service) { + mIRemotePlayService = IRemotePlayService.Stub.asInterface(service); + } + + public void onServiceDisconnected(ComponentName className) { + mIRemotePlayService = null; + } + }; + + private static final ArrayList CONTROL_FILTERS; + static { + IntentFilter f = new IntentFilter(); + f.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK); + f.addAction(MediaControlIntent.ACTION_PLAY); + f.addAction(MediaControlIntent.ACTION_PAUSE); + f.addAction(MediaControlIntent.ACTION_SEEK); + f.addAction(MediaControlIntent.ACTION_STOP); + f.addDataScheme("http"); + f.addDataScheme("https"); + try { + f.addDataType("video/*"); + f.addDataType("audio/*"); + } catch (MalformedMimeTypeException ex) { + throw new RuntimeException(ex); + } + + CONTROL_FILTERS = new ArrayList(); + CONTROL_FILTERS.add(f); + } - CONTROL_FILTERS = new ArrayList(); - CONTROL_FILTERS.add(f); - } - /** - * Listens for messages about devices. - */ - static private class DeviceListener extends Handler { - - private final WeakReference mService; + * Listens for messages about devices. + */ + static private class DeviceListener extends Handler { - DeviceListener(Provider provider) { - mService = new WeakReference(provider); - } - - @Override - public void handleMessage(Message msg) { - if (mService.get() != null) - mService.get().handleMessage(msg); - } - } - - final Messenger mListener = new Messenger(new DeviceListener(this)); + private final WeakReference mService; - public Provider(Context context) { - super(context); - context.bindService( - new Intent(context, RemotePlayService.class), - mConnection, - Context.BIND_AUTO_CREATE - ); - } + DeviceListener(Provider provider) { + mService = new WeakReference(provider); + } + + @Override + public void handleMessage(Message msg) { + if (mService.get() != null) + mService.get().handleMessage(msg); + } + } + + final Messenger mListener = new Messenger(new DeviceListener(this)); + + public Provider(Context context) { + super(context); + context.bindService( + new Intent(context, RemotePlayService.class), + mConnection, + Context.BIND_AUTO_CREATE + ); + } public void close() { getContext().unbindService(mConnection); } - - @Override - public void onDiscoveryRequestChanged(MediaRouteDiscoveryRequest request) { - try { - if (request != null && request.isActiveScan()) + + @Override + public void onDiscoveryRequestChanged(MediaRouteDiscoveryRequest request) { + try { + if (request != null && request.isActiveScan()) mIRemotePlayService.startSearch(mListener); } catch (RemoteException e) { e.printStackTrace(); } - } + } - @Override - public RouteController onCreateRouteController(String routeId) { - return new RouteController(routeId); - } + @Override + public RouteController onCreateRouteController(String routeId) { + return new RouteController(routeId); + } - private void updateRoutes() { - Builder builder = new Builder(); - for (Entry d : mDevices.entrySet()) { - MediaRouteDescriptor routeDescriptor = new MediaRouteDescriptor.Builder( - d.getValue().id, - d.getValue().name) - .setDescription(getContext().getResources() - .getString(R.string.route_description)) - .addControlFilters(CONTROL_FILTERS) - .setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE) - .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE) - .setVolumeMax(d.getValue().volumeMax) - .setVolume(d.getValue().volume) - .build(); - builder.addRoute(routeDescriptor); - } - setDescriptor(builder.build()); - } + private void updateRoutes() { + Builder builder = new Builder(); + for (Entry d : mDevices.entrySet()) { + MediaRouteDescriptor routeDescriptor = new MediaRouteDescriptor.Builder( + d.getValue().id, + d.getValue().name) + .setDescription(getContext().getResources() + .getString(R.string.route_description)) + .addControlFilters(CONTROL_FILTERS) + .setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE) + .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE) + .setVolumeMax(d.getValue().volumeMax) + .setVolume(d.getValue().volume) + .build(); + builder.addRoute(routeDescriptor); + } + setDescriptor(builder.build()); + } - /** - * Receives and forwards device selections, volume change - * requests and control requests. - */ - private final class RouteController extends MediaRouteProvider.RouteController { - private final String mRouteId; + /** + * Receives and forwards device selections, volume change + * requests and control requests. + */ + private final class RouteController extends MediaRouteProvider.RouteController { - public RouteController(String routeId) { - mRouteId = routeId; - } + private final String mRouteId; - @Override - public void onRelease() { - } + public RouteController(String routeId) { + mRouteId = routeId; + } - @Override - public void onSelect() { - try { + @Override + public void onRelease() { + } + + @Override + public void onSelect() { + try { mIRemotePlayService.selectRenderer(mRouteId); } catch (RemoteException e) { e.printStackTrace(); } - } + } - @Override - public void onUnselect() { - try { + @Override + public void onUnselect() { + try { mIRemotePlayService.unselectRenderer(mRouteId); } catch (RemoteException e) { e.printStackTrace(); } - } + } - @Override - public void onSetVolume(int volume) { - if (volume < 0 || volume > mDevices.get(mRouteId).volumeMax) - return; - - try { + @Override + public void onSetVolume(int volume) { + if (volume < 0 || volume > mDevices.get(mRouteId).volumeMax) + return; + + try { mIRemotePlayService.setVolume(volume); } catch (RemoteException e) { e.printStackTrace(); } - mDevices.get(mRouteId).volume = volume; - updateRoutes(); - } + mDevices.get(mRouteId).volume = volume; + updateRoutes(); + } - @Override - public void onUpdateVolume(int delta) { - onSetVolume(mDevices.get(mRouteId).volume + delta); - } + @Override + public void onUpdateVolume(int delta) { + onSetVolume(mDevices.get(mRouteId).volume + delta); + } - /** - * Handles play, pause, resume, stop, seek and get_status requests for this route. - */ - @Override - public boolean onControlRequest(Intent intent, ControlRequestCallback callback) { - try { - if (intent.getAction().equals(MediaControlIntent.ACTION_PLAY)) { - String metadata = (intent.hasExtra(MediaControlIntent.EXTRA_ITEM_METADATA)) - ? intent.getExtras().getString(MediaControlIntent.EXTRA_ITEM_METADATA) - : null; - mIRemotePlayService.play(intent.getDataString(), metadata); - // Store in intent extras for later. - intent.putExtra(MediaControlIntent.EXTRA_SESSION_ID, mRouteId); - intent.putExtra(MediaControlIntent.EXTRA_ITEM_ID, intent.getDataString()); - getItemStatus(intent, callback); - return true; - } - else if (intent.getAction().equals(MediaControlIntent.ACTION_PAUSE)) { + /** + * Handles play, pause, resume, stop, seek and get_status requests for this route. + */ + @Override + public boolean onControlRequest(Intent intent, ControlRequestCallback callback) { + try { + if (intent.getAction().equals(MediaControlIntent.ACTION_PLAY)) { + String metadata = (intent.hasExtra(MediaControlIntent.EXTRA_ITEM_METADATA)) + ? intent.getExtras().getString(MediaControlIntent.EXTRA_ITEM_METADATA) + : null; + mIRemotePlayService.play(intent.getDataString(), metadata); + // Store in intent extras for later. + intent.putExtra(MediaControlIntent.EXTRA_SESSION_ID, mRouteId); + intent.putExtra(MediaControlIntent.EXTRA_ITEM_ID, intent.getDataString()); + getItemStatus(intent, callback); + return true; + } + else if (intent.getAction().equals(MediaControlIntent.ACTION_PAUSE)) { mIRemotePlayService.pause(mRouteId); - return true; - } - else if (intent.getAction().equals(MediaControlIntent.ACTION_RESUME)) { - mIRemotePlayService.resume(mRouteId); - return true; - } - else if (intent.getAction().equals(MediaControlIntent.ACTION_STOP)) { - mIRemotePlayService.stop(mRouteId); - return true; - } - else if (intent.getAction().equals(MediaControlIntent.ACTION_SEEK)) { - mIRemotePlayService.seek(mRouteId, - intent.getStringExtra( - MediaControlIntent.EXTRA_ITEM_ID), - intent.getLongExtra( - MediaControlIntent.EXTRA_ITEM_CONTENT_POSITION, 0)); - getItemStatus(intent, callback); - return true; - } - else if(intent.getAction().equals(MediaControlIntent.ACTION_GET_STATUS)) { - getItemStatus(intent, callback); - return true; - } + return true; + } + else if (intent.getAction().equals(MediaControlIntent.ACTION_RESUME)) { + mIRemotePlayService.resume(mRouteId); + return true; + } + else if (intent.getAction().equals(MediaControlIntent.ACTION_STOP)) { + mIRemotePlayService.stop(mRouteId); + return true; + } + else if (intent.getAction().equals(MediaControlIntent.ACTION_SEEK)) { + mIRemotePlayService.seek(mRouteId, + intent.getStringExtra( + MediaControlIntent.EXTRA_ITEM_ID), + intent.getLongExtra( + MediaControlIntent.EXTRA_ITEM_CONTENT_POSITION, 0)); + getItemStatus(intent, callback); + return true; + } + else if(intent.getAction().equals(MediaControlIntent.ACTION_GET_STATUS)) { + getItemStatus(intent, callback); + return true; + } } catch (RemoteException e) { e.printStackTrace(); } return false; - } - } - - /** - * Requests status info via RemotePlayService, stores intent and callback to - * access later in handleMessage. - */ - private void getItemStatus(Intent intent, ControlRequestCallback callback) - throws RemoteException { - if (callback == null) - return; + } - Pair pair = - new Pair(intent, callback); - int r = new Random().nextInt(); - mRequests.put(r, pair); - mIRemotePlayService.getItemStatus( - intent.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID), - intent.getStringExtra(MediaControlIntent.EXTRA_ITEM_ID), - r); - } - - /** - * Handles device add and remove as well as sending status info requested earlier. - */ - public void handleMessage(Message msg) { - Bundle data = msg.getData(); + } + + /** + * Requests status info via RemotePlayService, stores intent and callback to + * access later in handleMessage. + */ + private void getItemStatus(Intent intent, ControlRequestCallback callback) + throws RemoteException { + if (callback == null) + return; + + Pair pair = + new Pair(intent, callback); + int r = new Random().nextInt(); + mRequests.put(r, pair); + mIRemotePlayService.getItemStatus( + intent.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID), + intent.getStringExtra(MediaControlIntent.EXTRA_ITEM_ID), + r); + } + + /** + * Handles device add and remove as well as sending status info requested earlier. + */ + public void handleMessage(Message msg) { + Bundle data = msg.getData(); switch (msg.what) { - case MSG_RENDERER_ADDED: - msg.getData().setClassLoader(Device.class.getClassLoader()); - Device device = (Device) data.getParcelable("device"); - mDevices.put(device.id, device); - updateRoutes(); - break; - case MSG_RENDERER_REMOVED: - mDevices.remove(data.getString("id")); - updateRoutes(); - break; - case MSG_STATUS_INFO: - Pair pair = - mRequests.get(data.getInt("hash")); - Bundle status = data.getBundle("media_item_status"); + case MSG_RENDERER_ADDED: + msg.getData().setClassLoader(Device.class.getClassLoader()); + Device device = (Device) data.getParcelable("device"); + mDevices.put(device.id, device); + updateRoutes(); + break; + case MSG_RENDERER_REMOVED: + mDevices.remove(data.getString("id")); + updateRoutes(); + break; + case MSG_STATUS_INFO: + Pair pair = + mRequests.get(data.getInt("hash")); + Bundle status = data.getBundle("media_item_status"); - if (pair.first.hasExtra(MediaControlIntent.EXTRA_SESSION_ID)) { - status.putString(MediaControlIntent.EXTRA_SESSION_ID, - pair.first.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID)); - } - if (pair.first.hasExtra(MediaControlIntent.EXTRA_ITEM_ID)) { - status.putString(MediaControlIntent.EXTRA_ITEM_ID, - pair.first.getStringExtra(MediaControlIntent.EXTRA_ITEM_ID)); - } - pair.second.onResult(status); - break; + if (pair.first.hasExtra(MediaControlIntent.EXTRA_SESSION_ID)) + status.putString(MediaControlIntent.EXTRA_SESSION_ID, + pair.first.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID)); + if (pair.first.hasExtra(MediaControlIntent.EXTRA_ITEM_ID)) + status.putString(MediaControlIntent.EXTRA_ITEM_ID, + pair.first.getStringExtra(MediaControlIntent.EXTRA_ITEM_ID)); + pair.second.onResult(status); + break; case MSG_ERROR: Toast.makeText(getContext(), data.getString("error"), Toast.LENGTH_SHORT).show(); break; - } - - } - + } + + } + } \ No newline at end of file diff --git a/src/com/github/nutomic/controldlna/upnp/ProviderService.java b/src/com/github/nutomic/controldlna/upnp/ProviderService.java index 1d77864..44085f0 100644 --- a/src/com/github/nutomic/controldlna/upnp/ProviderService.java +++ b/src/com/github/nutomic/controldlna/upnp/ProviderService.java @@ -4,12 +4,12 @@ All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * Neither the name of the nor the + * Neither the name of the nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. @@ -33,18 +33,19 @@ import android.support.v7.media.MediaRouteProviderService; public class ProviderService extends MediaRouteProviderService { private Provider mProvider; + @Override public MediaRouteProvider onCreateMediaRouteProvider() { - if (mProvider == null) { + if (mProvider == null) mProvider = new Provider(this); - } return mProvider; } - + @Override public void onDestroy() { super.onDestroy(); mProvider.close(); mProvider = null; } + } diff --git a/src/com/github/nutomic/controldlna/upnp/RemotePlayService.java b/src/com/github/nutomic/controldlna/upnp/RemotePlayService.java index 608e8d1..ff080fa 100644 --- a/src/com/github/nutomic/controldlna/upnp/RemotePlayService.java +++ b/src/com/github/nutomic/controldlna/upnp/RemotePlayService.java @@ -4,12 +4,12 @@ All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * Neither the name of the nor the + * Neither the name of the nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. @@ -61,7 +61,6 @@ import android.os.Messenger; import android.os.RemoteException; import android.util.Log; - /** * Allows UPNP playback from different apps by providing a proxy interface. * You can communicate to this service via RemotePlayServiceBinder. @@ -72,139 +71,133 @@ import android.util.Log; public class RemotePlayService extends Service implements RegistryListener { private static final String TAG = "RemotePlayService"; - - Messenger mListener; - - ConcurrentHashMap> mDevices = - new ConcurrentHashMap>(); - - protected AndroidUpnpService mUpnpService; - private ServiceConnection mUpnpServiceConnection = new ServiceConnection() { + Messenger mListener; - /** - * Registers DeviceListener, adds known devices and starts search if requested. - */ + ConcurrentHashMap> mDevices = + new ConcurrentHashMap>(); + + protected AndroidUpnpService mUpnpService; + + private ServiceConnection mUpnpServiceConnection = new ServiceConnection() { + + /** + * Registers DeviceListener, adds known devices and starts search if requested. + */ public void onServiceConnected(ComponentName className, IBinder service) { - mUpnpService = (AndroidUpnpService) service; - mUpnpService.getRegistry().addListener(RemotePlayService.this); - for (Device d : mUpnpService.getControlPoint().getRegistry().getDevices()) { - if (d instanceof LocalDevice) - localDeviceAdded(mUpnpService.getRegistry(), (LocalDevice) d); - else - remoteDeviceAdded(mUpnpService.getRegistry(), (RemoteDevice) d); - } - mUpnpService.getControlPoint().search(); - } + mUpnpService = (AndroidUpnpService) service; + mUpnpService.getRegistry().addListener(RemotePlayService.this); + for (Device d : mUpnpService.getControlPoint().getRegistry().getDevices()) + if (d instanceof LocalDevice) + localDeviceAdded(mUpnpService.getRegistry(), (LocalDevice) d); + else + remoteDeviceAdded(mUpnpService.getRegistry(), (RemoteDevice) d); + mUpnpService.getControlPoint().search(); + } - public void onServiceDisconnected(ComponentName className) { - mUpnpService = null; - } - }; - + public void onServiceDisconnected(ComponentName className) { + mUpnpService = null; + } + }; + + /** + * All active binders. The Hashmap value is unused. + */ + WeakHashMap mBinders = + new WeakHashMap(); - /** - * All active binders. The Hashmap value is unused. - */ - WeakHashMap mBinders = - new WeakHashMap(); - @Override public IBinder onBind(Intent itnent) { RemotePlayServiceBinder b = new RemotePlayServiceBinder(this); mBinders.put(b, true); return b; } - + /** * Binds to cling service, registers wifi state change listener. */ @Override public void onCreate() { super.onCreate(); - bindService( - new Intent(this, AndroidUpnpServiceImpl.class), - mUpnpServiceConnection, - Context.BIND_AUTO_CREATE - ); - - IntentFilter filter = new IntentFilter(); - filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); - filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); - registerReceiver(mWifiReceiver, filter); + bindService( + new Intent(this, AndroidUpnpServiceImpl.class), + mUpnpServiceConnection, + Context.BIND_AUTO_CREATE + ); + + IntentFilter filter = new IntentFilter(); + filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); + filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); + registerReceiver(mWifiReceiver, filter); } - + @Override public void onDestroy() { super.onDestroy(); - unbindService(mUpnpServiceConnection); - unregisterReceiver(mWifiReceiver); + unbindService(mUpnpServiceConnection); + unregisterReceiver(mWifiReceiver); } - + /** * Sends msg via Messenger to Provider. */ void sendMessage(Message msg) { try { - mListener.send(msg); - } catch (RemoteException e) { - e.printStackTrace(); - } + mListener.send(msg); + } catch (RemoteException e) { + e.printStackTrace(); + } } - + /** * Sends the error as a message via Messenger. * @param error */ void sendError(String error) { Message msg = Message.obtain(null, Provider.MSG_ERROR, 0, 0); - msg.getData().putString("error", error); - sendMessage(msg); + msg.getData().putString("error", error); + sendMessage(msg); } - + /** - * Starts device search on wifi connect, removes unreachable + * Starts device search on wifi connect, removes unreachable * devices on wifi disconnect. */ private BroadcastReceiver mWifiReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - ConnectivityManager connManager = (ConnectivityManager) - getSystemService(CONNECTIVITY_SERVICE); - NetworkInfo wifi = connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI); + @Override + public void onReceive(Context context, Intent intent) { + ConnectivityManager connManager = (ConnectivityManager) + getSystemService(CONNECTIVITY_SERVICE); + NetworkInfo wifi = connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI); - if (wifi.isConnected()) { - if (mUpnpService != null) { - for (Device d : mUpnpService.getControlPoint().getRegistry().getDevices()) - deviceAdded(d); - mUpnpService.getControlPoint().search(); - } - } - else { - for (Entry> d : mDevices.entrySet()) { - if (mUpnpService.getControlPoint().getRegistry() - .getDevice(new UDN(d.getKey()), false) == null) { - deviceRemoved(d.getValue()); - for (RemotePlayServiceBinder b : mBinders.keySet()) { - if (b.mCurrentRenderer.equals(d.getValue())) { - b.mSubscriptionCallback.end(); - b.mCurrentRenderer = null; - } - } - } - } - } - } + if (wifi.isConnected()) { + if (mUpnpService != null) { + for (Device d : mUpnpService.getControlPoint().getRegistry().getDevices()) + deviceAdded(d); + mUpnpService.getControlPoint().search(); + } + } else + for (Entry> d : mDevices.entrySet()) + if (mUpnpService.getControlPoint().getRegistry() + .getDevice(new UDN(d.getKey()), false) == null) { + deviceRemoved(d.getValue()); + for (RemotePlayServiceBinder b : mBinders.keySet()) + if (b.mCurrentRenderer.equals(d.getValue())) { + b.mSubscriptionCallback.end(); + b.mCurrentRenderer = null; + } + } + } }; - /** - * Returns a device service by name for direct queries. - */ + /** + * Returns a device service by name for direct queries. + */ org.teleal.cling.model.meta.Service getService( Device device, String name) { return device.findService( - new ServiceType("schemas-upnp-org", name)); + new ServiceType("schemas-upnp-org", name)); } /** @@ -213,52 +206,52 @@ public class RemotePlayService extends Service implements RegistryListener { private void deviceAdded(final Device device) { if (mDevices.containsValue(device)) return; - - final org.teleal.cling.model.meta.Service rc = + + final org.teleal.cling.model.meta.Service rc = getService(device, "RenderingControl"); if (rc == null || mListener == null) return; - - if (device.getType().getType().equals("MediaRenderer") && - device instanceof RemoteDevice) { - mDevices.put(device.getIdentity().getUdn().toString(), device); - try { - mUpnpService.getControlPoint().execute(new GetVolume(rc) { - - @SuppressWarnings("rawtypes") - @Override - public void failure(ActionInvocation invocation, - UpnpResponse operation, String defaultMessage) { - Log.w(TAG, "Failed to get current Volume: " + defaultMessage); - sendError("Failed to get current Volume: " + defaultMessage); - } - - @SuppressWarnings("rawtypes") - @Override - public void received(ActionInvocation invocation, int currentVolume) { - int maxVolume = 100; - if (rc.getStateVariable("Volume") != null) { - StateVariableAllowedValueRange volumeRange = - rc.getStateVariable("Volume").getTypeDetails().getAllowedValueRange(); - maxVolume = (int) volumeRange.getMaximum(); - } - - Message msg = Message.obtain(null, Provider.MSG_RENDERER_ADDED, 0, 0); - msg.getData().putParcelable("device", new Provider.Device( - device.getIdentity().getUdn().toString(), - device.getDisplayString(), - device.getDetails().getManufacturerDetails().getManufacturer(), - currentVolume, - maxVolume)); - sendMessage(msg); - } - }); - } - catch (IllegalArgumentException e) { - e.printStackTrace(); - return; - } + if (device.getType().getType().equals("MediaRenderer") && + device instanceof RemoteDevice) { + mDevices.put(device.getIdentity().getUdn().toString(), device); + + try { + mUpnpService.getControlPoint().execute(new GetVolume(rc) { + + @SuppressWarnings("rawtypes") + @Override + public void failure(ActionInvocation invocation, + UpnpResponse operation, String defaultMessage) { + Log.w(TAG, "Failed to get current Volume: " + defaultMessage); + sendError("Failed to get current Volume: " + defaultMessage); + } + + @SuppressWarnings("rawtypes") + @Override + public void received(ActionInvocation invocation, int currentVolume) { + int maxVolume = 100; + if (rc.getStateVariable("Volume") != null) { + StateVariableAllowedValueRange volumeRange = + rc.getStateVariable("Volume").getTypeDetails().getAllowedValueRange(); + maxVolume = (int) volumeRange.getMaximum(); + } + + Message msg = Message.obtain(null, Provider.MSG_RENDERER_ADDED, 0, 0); + msg.getData().putParcelable("device", new Provider.Device( + device.getIdentity().getUdn().toString(), + device.getDisplayString(), + device.getDetails().getManufacturerDetails().getManufacturer(), + currentVolume, + maxVolume)); + sendMessage(msg); + } + }); + } + catch (IllegalArgumentException e) { + e.printStackTrace(); + return; + } } } @@ -266,25 +259,25 @@ public class RemotePlayService extends Service implements RegistryListener { * Remove the device from Provider. */ private void deviceRemoved(Device device) { - if (device.getType().getType().equals("MediaRenderer") && + if (device.getType().getType().equals("MediaRenderer") && device instanceof RemoteDevice) { Message msg = Message.obtain(null, Provider.MSG_RENDERER_REMOVED, 0, 0); String udn = device.getIdentity().getUdn().toString(); - msg.getData().putString("id", udn); - mDevices.remove(udn); - sendMessage(msg); + msg.getData().putString("id", udn); + mDevices.remove(udn); + sendMessage(msg); } } /** - * If a device was updated, we just add it again (devices are stored in + * If a device was updated, we just add it again (devices are stored in * maps, so adding the same one again just overwrites the old one). */ private void deviceUpdated(Device device) { deviceAdded(device); } - + @Override public void afterShutdown() { } @@ -327,4 +320,5 @@ public class RemotePlayService extends Service implements RegistryListener { public void remoteDeviceUpdated(Registry registry, RemoteDevice device) { deviceUpdated(device); } + } diff --git a/src/com/github/nutomic/controldlna/upnp/RemotePlayServiceBinder.java b/src/com/github/nutomic/controldlna/upnp/RemotePlayServiceBinder.java index 87f0cb7..b060787 100644 --- a/src/com/github/nutomic/controldlna/upnp/RemotePlayServiceBinder.java +++ b/src/com/github/nutomic/controldlna/upnp/RemotePlayServiceBinder.java @@ -4,12 +4,12 @@ All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * Neither the name of the nor the + * Neither the name of the nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. @@ -66,40 +66,39 @@ import android.util.Log; * */ public class RemotePlayServiceBinder extends IRemotePlayService.Stub { - + private static final String TAG = "RemotePlayServiceBinder"; - - Device mCurrentRenderer; - - private int mPlaybackState; - - private boolean mManuallyStopped; - + + Device mCurrentRenderer; + + private int mPlaybackState; + + private boolean mManuallyStopped; + SubscriptionCallback mSubscriptionCallback; private RemotePlayService mRps; - + public RemotePlayServiceBinder(RemotePlayService rps) { mRps = rps; } - + @Override public void startSearch(Messenger listener) throws RemoteException { - mRps.mListener = listener; + mRps.mListener = listener; } @Override public void selectRenderer(String id) throws RemoteException { mCurrentRenderer = mRps.mDevices.get(id); - for (RemotePlayServiceBinder b : mRps.mBinders.keySet()) { + for (RemotePlayServiceBinder b : mRps.mBinders.keySet()) if (b != this && mCurrentRenderer.equals(b.mCurrentRenderer)) b.unselectRenderer(""); - } - + mSubscriptionCallback = new SubscriptionCallback( mCurrentRenderer.findService( - new ServiceType("schemas-upnp-org", "AVTransport")), 600) { + new ServiceType("schemas-upnp-org", "AVTransport")), 600) { @SuppressWarnings("rawtypes") @Override @@ -109,69 +108,69 @@ public class RemotePlayServiceBinder extends IRemotePlayService.Stub { @SuppressWarnings("rawtypes") @Override protected void ended(GENASubscription sub, CancelReason reason, - UpnpResponse response) { + UpnpResponse response) { } @SuppressWarnings("rawtypes") @Override - protected void eventReceived(final GENASubscription sub) { + protected void eventReceived(final GENASubscription sub) { @SuppressWarnings("unchecked") Map m = sub.getCurrentValues(); try { LastChange lastChange = new LastChange( - new AVTransportLastChangeParser(), + new AVTransportLastChangeParser(), m.get("LastChange").toString()); - if (lastChange.getEventedValue(0, + if (lastChange.getEventedValue(0, AVTransportVariable.TransportState.class) == null) return; - - switch (lastChange.getEventedValue(0, + + switch (lastChange.getEventedValue(0, AVTransportVariable.TransportState.class) - .getValue()) { - case PLAYING: - mPlaybackState = MediaItemStatus.PLAYBACK_STATE_PLAYING; - break; - case PAUSED_PLAYBACK: - mPlaybackState = MediaItemStatus.PLAYBACK_STATE_PAUSED; - break; - case STOPPED: - if (mManuallyStopped) { - mManuallyStopped = false; - mPlaybackState = MediaItemStatus.PLAYBACK_STATE_CANCELED; - } - else - mPlaybackState = MediaItemStatus.PLAYBACK_STATE_FINISHED; - break; - case TRANSITIONING: - mPlaybackState = MediaItemStatus.PLAYBACK_STATE_PENDING; - break; - case NO_MEDIA_PRESENT: - mPlaybackState = MediaItemStatus.PLAYBACK_STATE_ERROR; - break; - default: - } - + .getValue()) { + case PLAYING: + mPlaybackState = MediaItemStatus.PLAYBACK_STATE_PLAYING; + break; + case PAUSED_PLAYBACK: + mPlaybackState = MediaItemStatus.PLAYBACK_STATE_PAUSED; + break; + case STOPPED: + if (mManuallyStopped) { + mManuallyStopped = false; + mPlaybackState = MediaItemStatus.PLAYBACK_STATE_CANCELED; + } + else + mPlaybackState = MediaItemStatus.PLAYBACK_STATE_FINISHED; + break; + case TRANSITIONING: + mPlaybackState = MediaItemStatus.PLAYBACK_STATE_PENDING; + break; + case NO_MEDIA_PRESENT: + mPlaybackState = MediaItemStatus.PLAYBACK_STATE_ERROR; + break; + default: + } + } catch (Exception e) { Log.w(TAG, "Failed to parse UPNP event", e); mRps.sendError("Failed to parse UPNP event"); - } + } } @SuppressWarnings("rawtypes") @Override - protected void eventsMissed(GENASubscription sub, - int numberOfMissedEvents) { + protected void eventsMissed(GENASubscription sub, + int numberOfMissedEvents) { } @SuppressWarnings("rawtypes") @Override protected void failed(GENASubscription sub, UpnpResponse responseStatus, - Exception exception, String defaultMsg) { + Exception exception, String defaultMsg) { Log.w(TAG, "Register Subscription Callback failed: " + defaultMsg, exception); mRps.sendError("Register Subscription Callback failed: " + defaultMsg); } }; - mRps.mUpnpService.getControlPoint().execute(mSubscriptionCallback); + mRps.mUpnpService.getControlPoint().execute(mSubscriptionCallback); } /** @@ -183,70 +182,70 @@ public class RemotePlayServiceBinder extends IRemotePlayService.Stub { stop(sessionId); if (mSubscriptionCallback != null) mSubscriptionCallback.end(); - mCurrentRenderer = null; + mCurrentRenderer = null; } /** - * Sets an absolute volume. The value is assumed to be within the valid - * volume range. - */ + * Sets an absolute volume. The value is assumed to be within the valid + * volume range. + */ @Override public void setVolume(int volume) throws RemoteException { mRps.mUpnpService.getControlPoint().execute( - new SetVolume(mRps.getService(mCurrentRenderer, + new SetVolume(mRps.getService(mCurrentRenderer, "RenderingControl"), volume) { - - @SuppressWarnings("rawtypes") - @Override - public void failure(ActionInvocation invocation, - UpnpResponse operation, String defaultMessage) { - Log.w(TAG, "Set volume failed: " + defaultMessage); - mRps.sendError("Set volume failed: " + defaultMessage); - } - }); + + @SuppressWarnings("rawtypes") + @Override + public void failure(ActionInvocation invocation, + UpnpResponse operation, String defaultMessage) { + Log.w(TAG, "Set volume failed: " + defaultMessage); + mRps.sendError("Set volume failed: " + defaultMessage); + } + }); } /** - * Sets playback source and metadata, then starts playing on + * Sets playback source and metadata, then starts playing on * current renderer. */ @Override public void play(String uri, String metadata) throws RemoteException { mPlaybackState = MediaItemStatus.PLAYBACK_STATE_BUFFERING; mRps.mUpnpService.getControlPoint().execute(new SetAVTransportURI( - mRps.getService(mCurrentRenderer, "AVTransport"), - uri, metadata) { + mRps.getService(mCurrentRenderer, "AVTransport"), + uri, metadata) { @SuppressWarnings("rawtypes") @Override - public void failure(ActionInvocation invocation, - UpnpResponse operation, String defaultMsg) { - Log.w(TAG, "Set URI failed: " + defaultMsg); - mRps.sendError("Set URI failed: " + defaultMsg); - } - - @SuppressWarnings("rawtypes") - @Override - public void success(ActionInvocation invocation) { - mRps.mUpnpService.getControlPoint().execute( - new Play(mRps.getService(mCurrentRenderer, - "AVTransport")) { - - @Override - public void success(ActionInvocation invocation) { - mPlaybackState = MediaItemStatus.PLAYBACK_STATE_PLAYING; - } - - @Override - public void failure(ActionInvocation invocation, - UpnpResponse operation, String defaultMessage) { - Log.w(TAG, "Play failed: " + defaultMessage); - mRps.sendError("Play failed: " + defaultMessage); - } - }); + public void failure(ActionInvocation invocation, + UpnpResponse operation, String defaultMsg) { + Log.w(TAG, "Set URI failed: " + defaultMsg); + mRps.sendError("Set URI failed: " + defaultMsg); } - }); + + @SuppressWarnings("rawtypes") + @Override + public void success(ActionInvocation invocation) { + mRps.mUpnpService.getControlPoint().execute( + new Play(mRps.getService(mCurrentRenderer, + "AVTransport")) { + + @Override + public void success(ActionInvocation invocation) { + mPlaybackState = MediaItemStatus.PLAYBACK_STATE_PLAYING; + } + + @Override + public void failure(ActionInvocation invocation, + UpnpResponse operation, String defaultMessage) { + Log.w(TAG, "Play failed: " + defaultMessage); + mRps.sendError("Play failed: " + defaultMessage); + } + }); + } + }); } - + /** * Pauses playback on current renderer. */ @@ -254,37 +253,37 @@ public class RemotePlayServiceBinder extends IRemotePlayService.Stub { public void pause(final String sessionId) throws RemoteException { mRps.mUpnpService.getControlPoint().execute( new Pause(mRps.getService(mRps.mDevices.get(sessionId), "AVTransport")) { - - @SuppressWarnings("rawtypes") - @Override - public void failure(ActionInvocation invocation, - UpnpResponse operation, String defaultMessage) { - Log.w(TAG, "Pause failed, trying stop: " + defaultMessage); - mRps.sendError("Pause failed, trying stop: " + defaultMessage); - // Sometimes stop works even though pause does not. - try { - stop(sessionId); - } catch (RemoteException e) { - e.printStackTrace(); - } - } - }); + + @SuppressWarnings("rawtypes") + @Override + public void failure(ActionInvocation invocation, + UpnpResponse operation, String defaultMessage) { + Log.w(TAG, "Pause failed, trying stop: " + defaultMessage); + mRps.sendError("Pause failed, trying stop: " + defaultMessage); + // Sometimes stop works even though pause does not. + try { + stop(sessionId); + } catch (RemoteException e) { + e.printStackTrace(); + } + } + }); } @Override public void resume(String sessionId) throws RemoteException { mRps.mUpnpService.getControlPoint().execute( - new Play(mRps.getService(mRps.mDevices.get(sessionId), + new Play(mRps.getService(mRps.mDevices.get(sessionId), "AVTransport")) { - - @Override - @SuppressWarnings("rawtypes") - public void failure(ActionInvocation invocation, - UpnpResponse operation, String defaultMessage) { - Log.w(TAG, "Resume failed: " + defaultMessage); - mRps.sendError("Resume failed: " + defaultMessage); - } - }); + + @Override + @SuppressWarnings("rawtypes") + public void failure(ActionInvocation invocation, + UpnpResponse operation, String defaultMessage) { + Log.w(TAG, "Resume failed: " + defaultMessage); + mRps.sendError("Resume failed: " + defaultMessage); + } + }); } /** @@ -294,44 +293,44 @@ public class RemotePlayServiceBinder extends IRemotePlayService.Stub { public void stop(String sessionId) throws RemoteException { mManuallyStopped = true; mRps.mUpnpService.getControlPoint().execute( - new Stop(mRps.getService(mRps.mDevices.get(sessionId), "AVTransport")) { - + new Stop(mRps.getService(mRps.mDevices.get(sessionId), "AVTransport")) { + + @SuppressWarnings("rawtypes") + @Override + public void failure(ActionInvocation invocation, + org.teleal.cling.model.message.UpnpResponse operation, + String defaultMessage) { + Log.w(TAG, "Stop failed: " + defaultMessage); + mRps.sendError("Stop failed: " + defaultMessage); + } + }); + } + + /** + * Seeks to the given absolute time in seconds. + */ + @Override + public void seek(String sessionId, String itemId, long milliseconds) + throws RemoteException { + mRps.mUpnpService.getControlPoint().execute(new Seek( + mRps.getService(mRps.mDevices.get(sessionId), "AVTransport"), + SeekMode.REL_TIME, + Integer.toString((int) milliseconds / 1000)) { + @SuppressWarnings("rawtypes") @Override public void failure(ActionInvocation invocation, - org.teleal.cling.model.message.UpnpResponse operation, - String defaultMessage) { - Log.w(TAG, "Stop failed: " + defaultMessage); - mRps.sendError("Stop failed: " + defaultMessage); - } - }); - } - - /** - * Seeks to the given absolute time in seconds. - */ - @Override - public void seek(String sessionId, String itemId, long milliseconds) - throws RemoteException { - mRps.mUpnpService.getControlPoint().execute(new Seek( - mRps.getService(mRps.mDevices.get(sessionId), "AVTransport"), - SeekMode.REL_TIME, - Integer.toString((int) milliseconds / 1000)) { - - @SuppressWarnings("rawtypes") - @Override - public void failure(ActionInvocation invocation, UpnpResponse operation, String defaultMessage) { Log.w(TAG, "Seek failed: " + defaultMessage); mRps.sendError("Seek failed: " + defaultMessage); } - }); + }); } /** * Sends a message with current status for the route and item. * - * If itemId does not match with the item currently played, + * If itemId does not match with the item currently played, * MediaItemStatus.PLAYBACK_STATE_INVALIDATED is returned. * * @param sessionId Identifier of the session (equivalent to route) to get info for. @@ -339,42 +338,41 @@ public class RemotePlayServiceBinder extends IRemotePlayService.Stub { * @param requestHash Passed back in message to find original request object. */ @Override - public void getItemStatus(String sessionId, final String itemId, final int requestHash) + public void getItemStatus(String sessionId, final String itemId, final int requestHash) throws RemoteException { mRps.mUpnpService.getControlPoint().execute(new GetPositionInfo( - mRps.getService(mRps.mDevices.get(sessionId), "AVTransport")) { + mRps.getService(mRps.mDevices.get(sessionId), "AVTransport")) { - @SuppressWarnings("rawtypes") - @Override - public void failure(ActionInvocation invocation, - UpnpResponse operation, String defaultMessage) { - Log.w(TAG, "Get position failed: " + defaultMessage); - } + @SuppressWarnings("rawtypes") + @Override + public void failure(ActionInvocation invocation, + UpnpResponse operation, String defaultMessage) { + Log.w(TAG, "Get position failed: " + defaultMessage); + } - @SuppressWarnings("rawtypes") - @Override - public void received(ActionInvocation invocation, PositionInfo positionInfo) { - if (positionInfo.getTrackURI() == null) - return; - - Message msg = Message.obtain(null, Provider.MSG_STATUS_INFO, 0, 0); - Builder status = null; - - if (positionInfo.getTrackURI().equals(itemId)) { - status = new MediaItemStatus.Builder(mPlaybackState) - .setContentPosition(positionInfo.getTrackElapsedSeconds() * 1000) - .setContentDuration(positionInfo.getTrackDurationSeconds() * 1000) - .setTimestamp(positionInfo.getAbsCount()); - } - else { - status = new MediaItemStatus.Builder( - MediaItemStatus.PLAYBACK_STATE_INVALIDATED); - } - - msg.getData().putBundle("media_item_status", status.build().asBundle()); - msg.getData().putInt("hash", requestHash); - mRps.sendMessage(msg); - } + @SuppressWarnings("rawtypes") + @Override + public void received(ActionInvocation invocation, PositionInfo positionInfo) { + if (positionInfo.getTrackURI() == null) + return; + + Message msg = Message.obtain(null, Provider.MSG_STATUS_INFO, 0, 0); + Builder status = null; + + if (positionInfo.getTrackURI().equals(itemId)) + status = new MediaItemStatus.Builder(mPlaybackState) + .setContentPosition(positionInfo.getTrackElapsedSeconds() * 1000) + .setContentDuration(positionInfo.getTrackDurationSeconds() * 1000) + .setTimestamp(positionInfo.getAbsCount()); + else + status = new MediaItemStatus.Builder( + MediaItemStatus.PLAYBACK_STATE_INVALIDATED); + + msg.getData().putBundle("media_item_status", status.build().asBundle()); + msg.getData().putInt("hash", requestHash); + mRps.sendMessage(msg); + } }); } + }; \ No newline at end of file diff --git a/src/com/github/nutomic/controldlna/utility/DeviceArrayAdapter.java b/src/com/github/nutomic/controldlna/utility/DeviceArrayAdapter.java index bfe1fa4..d2b0fcb 100644 --- a/src/com/github/nutomic/controldlna/utility/DeviceArrayAdapter.java +++ b/src/com/github/nutomic/controldlna/utility/DeviceArrayAdapter.java @@ -4,12 +4,12 @@ All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * Neither the name of the nor the + * Neither the name of the nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. @@ -47,27 +47,26 @@ import android.widget.TextView; import com.github.nutomic.controldlna.R; - /** - * Displays the devices that are inserted through the RegistryListener (either + * Displays the devices that are inserted through the RegistryListener (either * of type RENDERER or SERVER). * * @author Felix Ableitner * */ -public class DeviceArrayAdapter extends ArrayAdapter> +public class DeviceArrayAdapter extends ArrayAdapter> implements RegistryListener { - + private static final String TAG = "DeviceArrayAdapter"; public static final String RENDERER = "MediaRenderer"; - + public static final String SERVER = "MediaServer"; - + private Activity mActivity; - + private String mDeviceType; - + /** * @param deviceType One of RENDERER or SERVER. */ @@ -76,46 +75,44 @@ public class DeviceArrayAdapter extends ArrayAdapter> mActivity = activity; mDeviceType = deviceType; } - + @Override public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { - LayoutInflater inflater = (LayoutInflater) getContext() - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - convertView = inflater.inflate(R.layout.list_item, parent, false); + LayoutInflater inflater = (LayoutInflater) getContext() + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + convertView = inflater.inflate(R.layout.list_item, parent, false); } - TextView tv = (TextView) convertView.findViewById(R.id.title); - RemoteImageView image = - (RemoteImageView) convertView.findViewById(R.id.image); - tv.setText(getItem(position).getDetails().getFriendlyName()); - - if (getItem(position).hasIcons()) { + TextView tv = (TextView) convertView.findViewById(R.id.title); + RemoteImageView image = + (RemoteImageView) convertView.findViewById(R.id.image); + tv.setText(getItem(position).getDetails().getFriendlyName()); + + if (getItem(position).hasIcons()) { URI uri = getItem(position).getIcons()[0].getUri(); - if (getItem(position) instanceof RemoteDevice) { + if (getItem(position) instanceof RemoteDevice) try { - RemoteDevice device = (RemoteDevice) getItem(position); + RemoteDevice device = (RemoteDevice) getItem(position); uri = device.normalizeURI(uri).toURI(); } catch (URISyntaxException e) { Log.w(TAG, "Failed to get device icon URI", e); } - } image.setImageUri(uri); - } - - return convertView; + } + + return convertView; } - + /** * Adds a new device to the list if its type equals mDeviceType. */ public void deviceAdded(final Device device) { - for (int i = 0; i < getCount(); i++) { + for (int i = 0; i < getCount(); i++) if (getItem(i).equals(device)) return; - } - + mActivity.runOnUiThread(new Runnable() { - + @Override public void run() { if (device.getType().getType().equals(mDeviceType)) @@ -124,18 +121,18 @@ public class DeviceArrayAdapter extends ArrayAdapter> }); } - /** + /** * Removes the device from the list (if it is an element). */ public void deviceRemoved(final Device device) { mActivity.runOnUiThread(new Runnable() { - + @Override public void run() { if (getPosition(device) != -1) - remove(device); + remove(device); } - }); + }); } @Override @@ -179,4 +176,5 @@ public class DeviceArrayAdapter extends ArrayAdapter> @Override public void afterShutdown() { } + } diff --git a/src/com/github/nutomic/controldlna/utility/FileArrayAdapter.java b/src/com/github/nutomic/controldlna/utility/FileArrayAdapter.java index ecd93f8..d513e00 100644 --- a/src/com/github/nutomic/controldlna/utility/FileArrayAdapter.java +++ b/src/com/github/nutomic/controldlna/utility/FileArrayAdapter.java @@ -4,12 +4,12 @@ All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * Neither the name of the nor the + * Neither the name of the nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. @@ -51,7 +51,7 @@ import com.github.nutomic.controldlna.R; * */ public class FileArrayAdapter extends ArrayAdapter { - + /** * Provides sorting of elements by track number. */ @@ -61,7 +61,7 @@ public class FileArrayAdapter extends ArrayAdapter { @Override public int compare(DIDLObject lhs, DIDLObject rhs) { - if (lhs instanceof MusicTrack && rhs instanceof MusicTrack) + if (lhs instanceof MusicTrack && rhs instanceof MusicTrack) return ((MusicTrack) rhs).getOriginalTrackNumber() - ((MusicTrack) lhs).getOriginalTrackNumber(); else if (lhs instanceof Item && rhs instanceof Container) @@ -75,37 +75,37 @@ public class FileArrayAdapter extends ArrayAdapter { } }); } - + /** * Returns a view with folder/media title, and artist name (for audio only). */ @Override public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { - LayoutInflater inflater = (LayoutInflater) getContext() - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - convertView = inflater.inflate(R.layout.list_item, parent, false); + LayoutInflater inflater = (LayoutInflater) getContext() + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + convertView = inflater.inflate(R.layout.list_item, parent, false); } DIDLObject item = getItem(position); - TextView title = (TextView) convertView.findViewById(R.id.title); - TextView artist = (TextView) convertView.findViewById(R.id.subtitle); - artist.setText(""); - RemoteImageView image = (RemoteImageView) convertView.findViewById(R.id.image); + TextView title = (TextView) convertView.findViewById(R.id.title); + TextView artist = (TextView) convertView.findViewById(R.id.subtitle); + artist.setText(""); + RemoteImageView image = (RemoteImageView) convertView.findViewById(R.id.image); if (item instanceof MusicTrack) { - MusicTrack track = (MusicTrack) item; - String trackNumber = (track.getOriginalTrackNumber() != null) - ? Integer.toString(track.getOriginalTrackNumber()) + ". " - : ""; - title.setText(trackNumber + item.getTitle()); - if (track.getArtists().length > 0) - artist.setText(track.getArtists()[0].getName()); + MusicTrack track = (MusicTrack) item; + String trackNumber = (track.getOriginalTrackNumber() != null) + ? Integer.toString(track.getOriginalTrackNumber()) + ". " + : ""; + title.setText(trackNumber + item.getTitle()); + if (track.getArtists().length > 0) + artist.setText(track.getArtists()[0].getName()); } - else - title.setText(item.getTitle()); - + else + title.setText(item.getTitle()); + image.setImageUri(item.getFirstPropertyValue( DIDLObject.Property.UPNP.ALBUM_ART_URI.class)); - return convertView; + return convertView; } /** @@ -115,5 +115,5 @@ public class FileArrayAdapter extends ArrayAdapter { for (DIDLObject d : playlist) add(d); } - + } diff --git a/src/com/github/nutomic/controldlna/utility/LoadImageTask.java b/src/com/github/nutomic/controldlna/utility/LoadImageTask.java index 0514b2b..17c22e9 100644 --- a/src/com/github/nutomic/controldlna/utility/LoadImageTask.java +++ b/src/com/github/nutomic/controldlna/utility/LoadImageTask.java @@ -4,12 +4,12 @@ All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * Neither the name of the nor the + * Neither the name of the nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. @@ -46,28 +46,28 @@ import android.util.Log; * */ public class LoadImageTask extends AsyncTask { - + private static final String TAG = "LoadImageTask"; - @Override - protected Bitmap doInBackground(URI... uri) { - if (uri[0] == null) - return null; - + @Override + protected Bitmap doInBackground(URI... uri) { + if (uri[0] == null) + return null; + Bitmap bm = null; - try { - URLConnection conn = new URL(uri[0].toString()) - .openConnection(); - conn.connect(); - InputStream is = conn.getInputStream(); - BufferedInputStream bis = new BufferedInputStream(is); - bm = BitmapFactory.decodeStream(bis); - bis.close(); - is.close(); - } catch (IOException e) { - Log.w(TAG, "Failed to load artwork image", e); - } - return bm; - } + try { + URLConnection conn = new URL(uri[0].toString()) + .openConnection(); + conn.connect(); + InputStream is = conn.getInputStream(); + BufferedInputStream bis = new BufferedInputStream(is); + bm = BitmapFactory.decodeStream(bis); + bis.close(); + is.close(); + } catch (IOException e) { + Log.w(TAG, "Failed to load artwork image", e); + } + return bm; + } } diff --git a/src/com/github/nutomic/controldlna/utility/RemoteImageView.java b/src/com/github/nutomic/controldlna/utility/RemoteImageView.java index 4c58eed..7313bad 100644 --- a/src/com/github/nutomic/controldlna/utility/RemoteImageView.java +++ b/src/com/github/nutomic/controldlna/utility/RemoteImageView.java @@ -4,12 +4,12 @@ All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * Neither the name of the nor the + * Neither the name of the nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. @@ -41,7 +41,7 @@ import android.widget.ImageView; * */ public class RemoteImageView extends ImageView { - + /** * Assigns the icon as image drawable when it is loaded. * @@ -49,28 +49,28 @@ public class RemoteImageView extends ImageView { * */ private class AssignImageTask extends LoadImageTask { - - @Override - protected void onPostExecute(Bitmap bm) { - if (bm != null) - setImageBitmap(bm); - else + + @Override + protected void onPostExecute(Bitmap bm) { + if (bm != null) + setImageBitmap(bm); + else setImageDrawable(null); - } - + } + }; - + public RemoteImageView(Context context) { super(context); } - + public RemoteImageView(Context context, AttributeSet attrs) { - super(context, attrs); - } - + super(context, attrs); + } + public RemoteImageView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - } + super(context, attrs, defStyle); + } /** * Sets the URI where the image should be loaded from, loads and assigns it. @@ -79,5 +79,5 @@ public class RemoteImageView extends ImageView { setImageDrawable(null); new AssignImageTask().execute(uri); } - + } diff --git a/src/com/github/nutomic/controldlna/utility/RouteAdapter.java b/src/com/github/nutomic/controldlna/utility/RouteAdapter.java index e9455a0..26125e3 100644 --- a/src/com/github/nutomic/controldlna/utility/RouteAdapter.java +++ b/src/com/github/nutomic/controldlna/utility/RouteAdapter.java @@ -17,22 +17,22 @@ public class RouteAdapter extends ArrayAdapter { public RouteAdapter(Context context) { super(context, R.layout.list_item); } - + @Override public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { - LayoutInflater inflater = (LayoutInflater) getContext() - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - convertView = inflater.inflate(R.layout.list_item, parent, false); + LayoutInflater inflater = (LayoutInflater) getContext() + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + convertView = inflater.inflate(R.layout.list_item, parent, false); } - - TextView title = (TextView) convertView.findViewById(R.id.title); - title.setText(getItem(position).getName()); - - TextView subtitle = (TextView) convertView.findViewById(R.id.subtitle); - subtitle.setText(getItem(position).getDescription()); - - return convertView; + + TextView title = (TextView) convertView.findViewById(R.id.title); + title.setText(getItem(position).getName()); + + TextView subtitle = (TextView) convertView.findViewById(R.id.subtitle); + subtitle.setText(getItem(position).getDescription()); + + return convertView; } /**