From 0a7bae6b058cfb8098a91f1896932d591079c5ba Mon Sep 17 00:00:00 2001 From: Scott Jackson Date: Sun, 9 Feb 2014 10:16:51 -0800 Subject: Added route manager abstraction, ChromeCast compat class for devices without Play Services --- .../dsub/fragments/DownloadFragment.java | 8 +- .../dsub/service/ChromeCastController.java | 70 +++++++++++++++++ .../daneren2005/dsub/service/DownloadService.java | 7 +- .../dsub/service/DownloadServiceImpl.java | 38 +++++---- .../daneren2005/dsub/util/MediaRouteManager.java | 91 ++++++++++++++++++++++ .../daneren2005/dsub/util/compat/CastCompat.java | 52 +++++++++++++ 6 files changed, 249 insertions(+), 17 deletions(-) create mode 100644 src/github/daneren2005/dsub/service/ChromeCastController.java create mode 100644 src/github/daneren2005/dsub/util/MediaRouteManager.java create mode 100644 src/github/daneren2005/dsub/util/compat/CastCompat.java (limited to 'src') diff --git a/src/github/daneren2005/dsub/fragments/DownloadFragment.java b/src/github/daneren2005/dsub/fragments/DownloadFragment.java index c5be820c..d3c1938e 100644 --- a/src/github/daneren2005/dsub/fragments/DownloadFragment.java +++ b/src/github/daneren2005/dsub/fragments/DownloadFragment.java @@ -505,7 +505,7 @@ public class DownloadFragment extends SubsonicFragment implements OnGestureListe if(downloadService != null) { MenuItem mediaRouteItem = menu.findItem(R.id.menu_mediaroute); MediaRouteButton mediaRouteButton = (MediaRouteButton) mediaRouteItem.getActionView(); - mediaRouteButton.setRouteSelector(downloadService.getRemotesAvailable()); + mediaRouteButton.setRouteSelector(downloadService.getRemoteSelector()); } } @@ -749,6 +749,9 @@ public class DownloadFragment extends SubsonicFragment implements OnGestureListe if(currentPlaying == null && downloadService != null && currentPlaying == downloadService.getCurrentPlaying()) { getImageLoader().loadImage(albumArtImageView, null, true, false); } + if(downloadService != null) { + downloadService.startRemoteScan(); + } } @Override @@ -758,6 +761,9 @@ public class DownloadFragment extends SubsonicFragment implements OnGestureListe if (visualizerView != null && visualizerView.isActive()) { visualizerView.setActive(false); } + if(getDownloadService() != null) { + getDownloadService().startRemoteScan(); + } } @Override diff --git a/src/github/daneren2005/dsub/service/ChromeCastController.java b/src/github/daneren2005/dsub/service/ChromeCastController.java new file mode 100644 index 00000000..467e4d7b --- /dev/null +++ b/src/github/daneren2005/dsub/service/ChromeCastController.java @@ -0,0 +1,70 @@ +/* + This file is part of Subsonic. + Subsonic is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Subsonic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Subsonic. If not, see . + Copyright 2014 (C) Scott Jackson +*/ + +package github.daneren2005.dsub.service; + +import android.os.Handler; + +/** + * Created by owner on 2/9/14. + */ +public class ChromeCastController extends RemoteController { + private CastDevice castDevice; + + public ChromeCastController(DownloadServiceImpl downloadService, CastDevice castDevice) { + this.downloadService = downloadService; + this.castDevice = castDevice; + } + + @Override + public void start() { + + } + + @Override + public void stop() { + + } + + @Override + public void shutdown() { + + } + + @Override + public void updatePlaylist() { + + } + + @Override + public void changePosition(int seconds) { + + } + + @Override + public void changeTrack(int index, DownloadFile song) { + + } + + @Override + public void setVolume(boolean up) { + + } + + @Override + public int getRemotePosition() { + return 0; + } +} diff --git a/src/github/daneren2005/dsub/service/DownloadService.java b/src/github/daneren2005/dsub/service/DownloadService.java index 1a96b2be..471b6d5d 100644 --- a/src/github/daneren2005/dsub/service/DownloadService.java +++ b/src/github/daneren2005/dsub/service/DownloadService.java @@ -29,6 +29,7 @@ import github.daneren2005.dsub.domain.MusicDirectory; import github.daneren2005.dsub.domain.PlayerState; import github.daneren2005.dsub.domain.RemoteControlState; import github.daneren2005.dsub.domain.RepeatMode; +import github.daneren2005.dsub.util.MediaRouteManager; /** * @author Sindre Mehus @@ -126,13 +127,17 @@ public interface DownloadService { VisualizerController getVisualizerController(); - MediaRouteSelector getRemotesAvailable(); + MediaRouteSelector getRemoteSelector(); boolean isRemoteEnabled(); void setRemoteEnabled(RemoteControlState newState); void setRemoteVolume(boolean up); + + void startRemoteScan(); + + void stopRemoteScan(); void setSleepTimerDuration(int duration); diff --git a/src/github/daneren2005/dsub/service/DownloadServiceImpl.java b/src/github/daneren2005/dsub/service/DownloadServiceImpl.java index ad2f0490..9a85bcdd 100644 --- a/src/github/daneren2005/dsub/service/DownloadServiceImpl.java +++ b/src/github/daneren2005/dsub/service/DownloadServiceImpl.java @@ -34,10 +34,10 @@ import github.daneren2005.dsub.domain.PlayerState; import github.daneren2005.dsub.domain.PodcastEpisode; import github.daneren2005.dsub.domain.RemoteControlState; import github.daneren2005.dsub.domain.RepeatMode; -import github.daneren2005.dsub.provider.JukeboxRouteProvider; import github.daneren2005.dsub.receiver.MediaButtonIntentReceiver; import github.daneren2005.dsub.util.CancellableTask; import github.daneren2005.dsub.util.Constants; +import github.daneren2005.dsub.util.MediaRouteManager; import github.daneren2005.dsub.util.ShufflePlayBuffer; import github.daneren2005.dsub.util.SimpleServiceBinder; import github.daneren2005.dsub.util.Util; @@ -64,9 +64,7 @@ import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.PowerManager; -import android.support.v7.media.MediaControlIntent; import android.support.v7.media.MediaRouteSelector; -import android.support.v7.media.MediaRouter; import android.util.Log; import android.support.v4.util.LruCache; import java.net.URLEncoder; @@ -140,7 +138,7 @@ public class DownloadServiceImpl extends Service implements DownloadService { private int timerDuration; private boolean autoPlayStart = false; - private MediaRouteSelector remoteSelector; + private MediaRouteManager mediaRouter; static { if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) { @@ -217,13 +215,7 @@ public class DownloadServiceImpl extends Service implements DownloadService { showVisualization = true; } - MediaRouter mediaRouter = MediaRouter.getInstance(this); - JukeboxRouteProvider routeProvider = new JukeboxRouteProvider(this); - mediaRouter.addProvider(routeProvider); - - MediaRouteSelector.Builder builder = new MediaRouteSelector.Builder(); - builder.addControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK); - remoteSelector = builder.build(); + mediaRouter = new MediaRouteManager(this); } @Override @@ -1132,8 +1124,8 @@ public class DownloadServiceImpl extends Service implements DownloadService { } @Override - public MediaRouteSelector getRemotesAvailable() { - return remoteSelector; + public MediaRouteSelector getRemoteSelector() { + return mediaRouter.getSelector(); } @Override @@ -1143,13 +1135,16 @@ public class DownloadServiceImpl extends Service implements DownloadService { @Override public void setRemoteEnabled(RemoteControlState newState) { - setRemoteState(newState); + setRemoteEnabled(newState, null); + } + public void setRemoteEnabled(RemoteControlState newState, Object ref) { + setRemoteState(newState, ref); SharedPreferences.Editor editor = Util.getPreferences(this).edit(); editor.putInt(Constants.PREFERENCES_KEY_CONTROL_MODE, newState.getValue()); editor.commit(); } - private void setRemoteState(RemoteControlState newState) { + private void setRemoteState(RemoteControlState newState, Object ref) { if(remoteController != null) { remoteController.stop(); setPlayerState(PlayerState.IDLE); @@ -1162,6 +1157,9 @@ public class DownloadServiceImpl extends Service implements DownloadService { case JUKEBOX_SERVER: remoteController = new JukeboxController(this, handler); break; + case CHROMECAST: + remoteController = (RemoteController) ref; + break; case LOCAL: default: break; } @@ -1188,6 +1186,16 @@ public class DownloadServiceImpl extends Service implements DownloadService { remoteController.setVolume(up); } + @Override + public void startRemoteScan() { + mediaRouter.startScan(); + } + + @Override + public void stopRemoteScan() { + mediaRouter.stopScan(); + } + private synchronized void bufferAndPlay() { bufferAndPlay(0); } diff --git a/src/github/daneren2005/dsub/util/MediaRouteManager.java b/src/github/daneren2005/dsub/util/MediaRouteManager.java new file mode 100644 index 00000000..ab6d6a10 --- /dev/null +++ b/src/github/daneren2005/dsub/util/MediaRouteManager.java @@ -0,0 +1,91 @@ +/* + This file is part of Subsonic. + Subsonic is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Subsonic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Subsonic. If not, see . + Copyright 2014 (C) Scott Jackson +*/ + +package github.daneren2005.dsub.util; + +import android.support.v7.media.MediaControlIntent; +import android.support.v7.media.MediaRouteSelector; +import android.support.v7.media.MediaRouter; + +import github.daneren2005.dsub.domain.RemoteControlState; +import github.daneren2005.dsub.provider.JukeboxRouteProvider; +import github.daneren2005.dsub.service.DownloadServiceImpl; +import github.daneren2005.dsub.service.RemoteController; +import github.daneren2005.dsub.util.compat.CastCompat; + +/** + * Created by owner on 2/8/14. + */ +public class MediaRouteManager extends MediaRouter.Callback { + private static boolean castAvailable = false; + + private DownloadServiceImpl downloadService; + private MediaRouter router; + private MediaRouteSelector selector; + + static { + try { + CastCompat.checkAvailable(); + castAvailable = true; + } catch(Throwable t) { + castAvailable = false; + } + } + + public MediaRouteManager(DownloadServiceImpl downloadService) { + this.downloadService = downloadService; + router = MediaRouter.getInstance(downloadService); + addProviders(); + buildSelector(); + } + + @Override + public void onRouteSelected(MediaRouter router, MediaRouter.RouteInfo info) { + if(castAvailable) { + RemoteController controller = CastCompat.getController(downloadService, info); + if(controller != null) { + downloadService.setRemoteEnabled(RemoteControlState.CHROMECAST, controller); + } + } + } + @Override + public void onRouteUnselected(MediaRouter router, MediaRouter.RouteInfo info) { + downloadService.setRemoteEnabled(RemoteControlState.LOCAL); + } + + public void startScan() { + router.addCallback(selector, this, MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN); + } + public void stopScan() { + router.removeCallback(this); + } + + public MediaRouteSelector getSelector() { + return selector; + } + + private void addProviders() { + JukeboxRouteProvider routeProvider = new JukeboxRouteProvider(downloadService); + router.addProvider(routeProvider); + } + private void buildSelector() { + MediaRouteSelector.Builder builder = new MediaRouteSelector.Builder(); + builder.addControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK); + if(castAvailable) { + builder.addControlCategory(CastCompat.getCastControlCategory()); + } + selector = builder.build(); + } +} diff --git a/src/github/daneren2005/dsub/util/compat/CastCompat.java b/src/github/daneren2005/dsub/util/compat/CastCompat.java new file mode 100644 index 00000000..0892040e --- /dev/null +++ b/src/github/daneren2005/dsub/util/compat/CastCompat.java @@ -0,0 +1,52 @@ +/* + This file is part of Subsonic. + Subsonic is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Subsonic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Subsonic. If not, see . + Copyright 2014 (C) Scott Jackson +*/ + +package github.daneren2005.dsub.util.compat; + +import android.support.v7.media.MediaRouter; + +import github.daneren2005.dsub.service.ChromeCastController; +import github.daneren2005.dsub.service.DownloadServiceImpl; +import github.daneren2005.dsub.service.RemoteController; + +/** + * Created by owner on 2/9/14. + */ +public final class CastCompat { + static { + try { + Class.forName("com.google.android.gms.cast.CastDevice"); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + + public static void checkAvailable() throws Throwable { + // Calling here forces class initialization. + } + + public static RemoteController getController(DownloadServiceImpl downloadService, MediaRouter.RouteInfo info) { + CastDevice device = CastDevice.getFromBundle(info.getExtras()); + if(device != null) { + return new ChromeCastController(downloadService, device); + } else { + return null; + } + } + + public static String getCastControlCategory() { + return CastMediaControlIntent.categoryForCast("5F85EBEB"); + } +} -- cgit v1.2.3