add chromecast support initialization logic and introduce chromecast preference
This commit is contained in:
parent
1b6459c8ee
commit
8061d94c1b
|
@ -0,0 +1,20 @@
|
|||
package de.danoeh.antennapod.config;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import de.danoeh.antennapod.activity.AudioplayerActivity;
|
||||
import de.danoeh.antennapod.core.CastCallbacks;
|
||||
|
||||
public class CastCallbacksImpl implements CastCallbacks {
|
||||
@Override
|
||||
public Class<? extends Activity> getCastActivity() {
|
||||
return AudioplayerActivity.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Intent getCastActivityIntent(Context context) {
|
||||
return new Intent(context, getCastActivity());
|
||||
}
|
||||
}
|
|
@ -16,5 +16,6 @@ public class ClientConfigurator {
|
|||
ClientConfig.playbackServiceCallbacks = new PlaybackServiceCallbacksImpl();
|
||||
ClientConfig.flattrCallbacks = new FlattrCallbacksImpl();
|
||||
ClientConfig.dbTasksCallbacks = new DBTasksCallbacksImpl();
|
||||
ClientConfig.castCallbacks = new CastCallbacksImpl();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -293,5 +293,14 @@
|
|||
android:key="prefAbout"
|
||||
android:title="@string/about_pref"/>
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory android:title="@string/experimental_pref">
|
||||
<de.danoeh.antennapod.preferences.SwitchCompatPreference
|
||||
android:defaultValue="false"
|
||||
android:enabled="true"
|
||||
android:key="prefCast"
|
||||
android:summary="@string/pref_cast_message"
|
||||
android:title="@string/pref_cast_title"/>
|
||||
</PreferenceCategory>
|
||||
|
||||
</PreferenceScreen>
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
package de.danoeh.antennapod.core;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
/**
|
||||
* Callbacks for the Cast features on the core module.
|
||||
*/
|
||||
public interface CastCallbacks {
|
||||
|
||||
Class<? extends Activity> getCastActivity();
|
||||
|
||||
Intent getCastActivityIntent(Context context);
|
||||
|
||||
}
|
|
@ -5,6 +5,7 @@ import android.content.Context;
|
|||
import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.storage.PodDBAdapter;
|
||||
import de.danoeh.antennapod.core.util.CastUtils;
|
||||
import de.danoeh.antennapod.core.util.NetworkUtils;
|
||||
|
||||
/**
|
||||
|
@ -30,6 +31,8 @@ public class ClientConfig {
|
|||
|
||||
public static DBTasksCallbacks dbTasksCallbacks;
|
||||
|
||||
public static CastCallbacks castCallbacks;
|
||||
|
||||
private static boolean initialized = false;
|
||||
|
||||
public static synchronized void initialize(Context context) {
|
||||
|
@ -41,6 +44,7 @@ public class ClientConfig {
|
|||
UpdateManager.init(context);
|
||||
PlaybackPreferences.init(context);
|
||||
NetworkUtils.init(context);
|
||||
CastUtils.initializeCastManager(context);
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -111,6 +111,7 @@ public class UserPreferences {
|
|||
public static final String PREF_SONIC = "prefSonic";
|
||||
public static final String PREF_STEREO_TO_MONO = "PrefStereoToMono";
|
||||
public static final String PREF_NORMALIZER = "prefNormalizer";
|
||||
public static final String PREF_CAST_ENABLED = "prefCast"; //Used for enabling Chromecast support
|
||||
public static final int EPISODE_CLEANUP_QUEUE = -1;
|
||||
public static final int EPISODE_CLEANUP_NULL = -2;
|
||||
public static final int EPISODE_CLEANUP_DEFAULT = 0;
|
||||
|
@ -493,16 +494,16 @@ public class UserPreferences {
|
|||
|
||||
public static void setVolume(int leftVolume, int rightVolume) {
|
||||
assert(0 <= leftVolume && leftVolume <= 100);
|
||||
assert(0 <= rightVolume && rightVolume <= 100);
|
||||
assert (0 <= rightVolume && rightVolume <= 100);
|
||||
prefs.edit()
|
||||
.putInt(PREF_LEFT_VOLUME, leftVolume)
|
||||
.putInt(PREF_LEFT_VOLUME, leftVolume)
|
||||
.putInt(PREF_RIGHT_VOLUME, rightVolume)
|
||||
.apply();
|
||||
}
|
||||
|
||||
public static void setAutodownloadSelectedNetworks(String[] value) {
|
||||
prefs.edit()
|
||||
.putString(PREF_AUTODL_SELECTED_NETWORKS, TextUtils.join(",", value))
|
||||
.putString(PREF_AUTODL_SELECTED_NETWORKS, TextUtils.join(",", value))
|
||||
.apply();
|
||||
}
|
||||
|
||||
|
@ -540,7 +541,7 @@ public class UserPreferences {
|
|||
throw new IllegalArgumentException("Flattr threshold must be in range [0.0, 1.0]");
|
||||
}
|
||||
prefs.edit()
|
||||
.putBoolean(PREF_AUTO_FLATTR, enabled)
|
||||
.putBoolean(PREF_AUTO_FLATTR, enabled)
|
||||
.putFloat(PREF_AUTO_FLATTR_PLAYED_DURATION_THRESHOLD, autoFlattrThreshold)
|
||||
.apply();
|
||||
}
|
||||
|
@ -800,4 +801,11 @@ public class UserPreferences {
|
|||
public static int readEpisodeCacheSize(String valueFromPrefs) {
|
||||
return readEpisodeCacheSizeInternal(valueFromPrefs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates whether Cast support (Chromecast, Audio Cast, etc) is enabled on the preferences.
|
||||
*/
|
||||
public static boolean isCastEnabled() {
|
||||
return prefs.getBoolean(PREF_CAST_ENABLED, false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,164 @@
|
|||
package de.danoeh.antennapod.core.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.net.Uri;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.v7.media.MediaRouter;
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.android.gms.cast.CastDevice;
|
||||
import com.google.android.gms.cast.CastMediaControlIntent;
|
||||
import com.google.android.gms.cast.MediaInfo;
|
||||
import com.google.android.gms.cast.MediaMetadata;
|
||||
import com.google.android.gms.common.images.WebImage;
|
||||
import com.google.android.libraries.cast.companionlibrary.cast.CastConfiguration;
|
||||
import com.google.android.libraries.cast.companionlibrary.cast.VideoCastManager;
|
||||
import com.google.android.libraries.cast.companionlibrary.cast.callbacks.VideoCastConsumer;
|
||||
import com.google.android.libraries.cast.companionlibrary.cast.callbacks.VideoCastConsumerImpl;
|
||||
|
||||
import java.util.Calendar;
|
||||
|
||||
import de.danoeh.antennapod.core.ClientConfig;
|
||||
import de.danoeh.antennapod.core.feed.FeedImage;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.util.playback.ExternalMedia;
|
||||
import de.danoeh.antennapod.core.util.playback.Playable;
|
||||
|
||||
/**
|
||||
* Helper functions for Cast support.
|
||||
*/
|
||||
public class CastUtils {
|
||||
private static final String TAG = "CastUtils";
|
||||
|
||||
public static final String CAST_APP_ID = CastMediaControlIntent.DEFAULT_MEDIA_RECEIVER_APPLICATION_ID;
|
||||
|
||||
public static final String KEY_MEDIA_ID = "CastUtils.Id";
|
||||
|
||||
public static void initializeCastManager(Context context){
|
||||
// TODO check for cast support enabled
|
||||
VideoCastManager.initialize(context, new CastConfiguration.Builder(CastUtils.CAST_APP_ID)
|
||||
.enableDebug()
|
||||
.enableLockScreen()
|
||||
.enableNotification()
|
||||
.enableWifiReconnection()
|
||||
.enableAutoReconnect()
|
||||
.setTargetActivity(ClientConfig.castCallbacks.getCastActivity())
|
||||
.build());
|
||||
VideoCastManager.getInstance().addVideoCastConsumer(castConsumer);
|
||||
PreferenceManager.getDefaultSharedPreferences(context)
|
||||
.registerOnSharedPreferenceChangeListener(changeListener);
|
||||
}
|
||||
|
||||
public static boolean isCastable(Playable media){
|
||||
if (media == null || media instanceof ExternalMedia) {
|
||||
return false;
|
||||
}
|
||||
if (media instanceof FeedMedia){
|
||||
String url = media.getStreamUrl();
|
||||
if(url == null || url.isEmpty()){
|
||||
return false;
|
||||
}
|
||||
switch (media.getMediaType()) {
|
||||
case UNKNOWN:
|
||||
return false;
|
||||
case AUDIO:
|
||||
return audioCapable;
|
||||
case VIDEO:
|
||||
return videoCapable;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts {@link FeedMedia} objects into a format suitable for sending to a Cast Device.
|
||||
* Before using this method, one should make sure {@link #isCastable(Playable)} returns
|
||||
* {@code true}.
|
||||
*
|
||||
* Unless media.{@link FeedMedia#loadMetadata() loadMetadata()} has already been called,
|
||||
* this method should not run on the main thread.
|
||||
*
|
||||
* @param media The {@link FeedMedia} object to be converted.
|
||||
* @return {@link MediaInfo} object in a format proper for casting.
|
||||
*/
|
||||
public static MediaInfo convertFromFeedMedia(FeedMedia media){
|
||||
if(media == null) {
|
||||
return null;
|
||||
}
|
||||
MediaMetadata metadata = new MediaMetadata(MediaMetadata.MEDIA_TYPE_GENERIC);
|
||||
try{
|
||||
media.loadMetadata();
|
||||
} catch (Playable.PlayableException e) {
|
||||
Log.e(TAG, "Unable to load FeedMedia metadata", e);
|
||||
}
|
||||
FeedItem feedItem = media.getItem();
|
||||
if (feedItem != null) {
|
||||
metadata.putString(MediaMetadata.KEY_TITLE, media.getEpisodeTitle());
|
||||
String subtitle = media.getFeedTitle();
|
||||
if (subtitle != null) {
|
||||
metadata.putString(MediaMetadata.KEY_SUBTITLE, subtitle);
|
||||
}
|
||||
FeedImage image = feedItem.getImage();
|
||||
if (image != null && image.getDownload_url() != null &&
|
||||
!image.getDownload_url().isEmpty()) {
|
||||
metadata.addImage(new WebImage(Uri.parse(image.getDownload_url())));
|
||||
}
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(media.getItem().getPubDate());
|
||||
metadata.putDate(MediaMetadata.KEY_RELEASE_DATE, calendar);
|
||||
|
||||
}
|
||||
//metadata.putString(MediaMetadata.KEY_ARTIST, null);
|
||||
metadata.putString(KEY_MEDIA_ID, media.getIdentifier().toString());
|
||||
|
||||
return new MediaInfo.Builder(media.getStreamUrl())
|
||||
.setContentType(media.getMime_type())
|
||||
.setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
|
||||
.setMetadata(metadata)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
private static SharedPreferences.OnSharedPreferenceChangeListener changeListener =
|
||||
(preference, key) -> {
|
||||
if (UserPreferences.PREF_CAST_ENABLED.equals(key)){
|
||||
if (UserPreferences.isCastEnabled()){
|
||||
// TODO enable all cast-related features
|
||||
} else {
|
||||
// TODO disable all cast-related features
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Ideally, all these fields and methods should be part of the CastManager implementation
|
||||
private static boolean videoCapable = true;
|
||||
private static boolean audioCapable = true;
|
||||
|
||||
public static boolean isVideoCapable(CastDevice device, boolean defaultValue){
|
||||
if (device == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
return device.hasCapability(CastDevice.CAPABILITY_VIDEO_OUT);
|
||||
}
|
||||
|
||||
public static boolean isAudioCapable(CastDevice device, boolean defaultValue){
|
||||
if (device == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
return device.hasCapability(CastDevice.CAPABILITY_AUDIO_OUT);
|
||||
}
|
||||
|
||||
private static VideoCastConsumer castConsumer = new VideoCastConsumerImpl() {
|
||||
@Override
|
||||
public void onDeviceSelected(CastDevice device, MediaRouter.RouteInfo routeInfo) {
|
||||
// If no device is selected, we assume both audio and video are castable
|
||||
videoCapable = isVideoCapable(device, true);
|
||||
audioCapable = isAudioCapable(device, true);
|
||||
}
|
||||
};
|
||||
|
||||
//TODO Queue handling perhaps
|
||||
}
|
|
@ -403,6 +403,8 @@
|
|||
<string name="pref_faq">FAQ</string>
|
||||
<string name="pref_known_issues">Known issues</string>
|
||||
<string name="pref_no_browser_found">No web browser found.</string>
|
||||
<string name="pref_cast_title">Cast support</string>
|
||||
<string name="pref_cast_message">Enable support for remote media playback on Cast devices (such as Chromecast, Audio Speakers or Android TV)</string>
|
||||
|
||||
<!-- Auto-Flattr dialog -->
|
||||
<string name="auto_flattr_enable">Enable automatic flattring</string>
|
||||
|
|
Loading…
Reference in New Issue