* add GooglePlayServices check

* implement wifi-reconnect feature for casting
* move wifiLock logic to abstract PSMP
This commit is contained in:
Domingos Lopes 2016-03-26 00:45:50 -04:00 committed by Domingos Lopes
parent af7526a409
commit 037b705075
7 changed files with 117 additions and 28 deletions

View File

@ -34,6 +34,8 @@ import android.widget.Toast;
import android.widget.ListView; import android.widget.ListView;
import com.afollestad.materialdialogs.MaterialDialog; import com.afollestad.materialdialogs.MaterialDialog;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.ArrayUtils;
@ -410,6 +412,22 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
ui.getActivity().startActivity(Intent.createChooser(emailIntent, intentTitle)); ui.getActivity().startActivity(Intent.createChooser(emailIntent, intentTitle));
return true; return true;
}); });
//checks whether Google Play Services is installed on the device (condition necessary for Cast support)
ui.findPreference(UserPreferences.PREF_CAST_ENABLED).setOnPreferenceChangeListener((preference, o) -> {
if (o instanceof Boolean && ((Boolean) o)) {
final int googlePlayServicesCheck = GoogleApiAvailability.getInstance()
.isGooglePlayServicesAvailable(ui.getActivity());
if (googlePlayServicesCheck == ConnectionResult.SUCCESS) {
return true;
} else {
GoogleApiAvailability.getInstance()
.getErrorDialog(ui.getActivity(), googlePlayServicesCheck, 0)
.show();
return false;
}
}
return true;
});
buildEpisodeCleanupPreference(); buildEpisodeCleanupPreference();
buildSmartMarkAsPlayedPreference(); buildSmartMarkAsPlayedPreference();
buildAutodownloadSelectedNetworsPreference(); buildAutodownloadSelectedNetworsPreference();

View File

@ -136,6 +136,7 @@ public class CastManager extends BaseCastManager implements OnFailedListener {
if (ConnectionResult.SUCCESS != GoogleApiAvailability.getInstance() if (ConnectionResult.SUCCESS != GoogleApiAvailability.getInstance()
.isGooglePlayServicesAvailable(context)) { .isGooglePlayServicesAvailable(context)) {
Log.e(TAG, "Couldn't find the appropriate version of Google Play Services"); Log.e(TAG, "Couldn't find the appropriate version of Google Play Services");
//TODO check whether creating an instance without google play services installed actually gives an exception
} }
INSTANCE = new CastManager(context, castConfiguration); INSTANCE = new CastManager(context, castConfiguration);
} }

View File

@ -2,7 +2,6 @@ package de.danoeh.antennapod.core.service.playback;
import android.content.Context; import android.content.Context;
import android.media.AudioManager; import android.media.AudioManager;
import android.net.wifi.WifiManager;
import android.os.PowerManager; import android.os.PowerManager;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.telephony.TelephonyManager; import android.telephony.TelephonyManager;
@ -56,11 +55,6 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer {
private final ThreadPoolExecutor executor; private final ThreadPoolExecutor executor;
/**
* A wifi-lock that is acquired if the media file is being streamed.
*/
private WifiManager.WifiLock wifiLock;
public LocalPSMP(@NonNull Context context, public LocalPSMP(@NonNull Context context,
@NonNull PSMPCallback callback) { @NonNull PSMPCallback callback) {
super(context, callback); super(context, callback);
@ -805,21 +799,9 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer {
}); });
} }
private synchronized void acquireWifiLockIfNecessary() { @Override
if (stream) { protected boolean shouldLockWifi(){
if (wifiLock == null) { return stream;
wifiLock = ((WifiManager) context.getSystemService(Context.WIFI_SERVICE))
.createWifiLock(WifiManager.WIFI_MODE_FULL, TAG);
wifiLock.setReferenceCounted(false);
}
wifiLock.acquire();
}
}
private synchronized void releaseWifiLockIfNecessary() {
if (wifiLock != null && wifiLock.isHeld()) {
wifiLock.release();
}
} }
private IPlayer setMediaPlayerListeners(IPlayer mp) { private IPlayer setMediaPlayerListeners(IPlayer mp) {
@ -878,13 +860,8 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer {
return callback.onMediaPlayerInfo(what); return callback.onMediaPlayerInfo(what);
} }
private final MediaPlayer.OnSpeedAdjustmentAvailableChangedListener private final MediaPlayer.OnSpeedAdjustmentAvailableChangedListener audioSetSpeedAbilityListener =
audioSetSpeedAbilityListener = new MediaPlayer.OnSpeedAdjustmentAvailableChangedListener() { (arg0, speedAdjustmentAvailable) -> callback.setSpeedAbilityChanged();
@Override
public void onSpeedAdjustmentAvailableChanged(MediaPlayer arg0, boolean speedAdjustmentAvailable) {
callback.setSpeedAbilityChanged();
}
};
private final MediaPlayer.OnErrorListener audioErrorListener = private final MediaPlayer.OnErrorListener audioErrorListener =

View File

@ -15,6 +15,8 @@ import android.graphics.Bitmap;
import android.graphics.BitmapFactory; import android.graphics.BitmapFactory;
import android.media.AudioManager; import android.media.AudioManager;
import android.media.MediaPlayer; import android.media.MediaPlayer;
import android.net.NetworkInfo;
import android.net.wifi.WifiManager;
import android.os.Binder; import android.os.Binder;
import android.os.Build; import android.os.Build;
import android.os.IBinder; import android.os.IBinder;
@ -60,6 +62,7 @@ import de.danoeh.antennapod.core.receiver.MediaButtonReceiver;
import de.danoeh.antennapod.core.storage.DBTasks; import de.danoeh.antennapod.core.storage.DBTasks;
import de.danoeh.antennapod.core.storage.DBWriter; import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.util.IntList; import de.danoeh.antennapod.core.util.IntList;
import de.danoeh.antennapod.core.util.NetworkUtils;
import de.danoeh.antennapod.core.util.QueueAccess; import de.danoeh.antennapod.core.util.QueueAccess;
import de.danoeh.antennapod.core.util.flattr.FlattrUtils; import de.danoeh.antennapod.core.util.flattr.FlattrUtils;
import de.danoeh.antennapod.core.util.playback.ExternalMedia; import de.danoeh.antennapod.core.util.playback.ExternalMedia;
@ -167,6 +170,12 @@ public class PlaybackService extends Service implements SharedPreferences.OnShar
*/ */
public static final int INVALID_TIME = -1; public static final int INVALID_TIME = -1;
/**
* Time in seconds during which the CastManager will try to reconnect to the Cast Device after
* the Wifi Connection is regained.
*/
private static final int RECONNECTION_ATTEMPT_PERIOD_S = 15;
/** /**
* Is true if service is running. * Is true if service is running.
*/ */
@ -188,6 +197,9 @@ public class PlaybackService extends Service implements SharedPreferences.OnShar
*/ */
private volatile PlaybackServiceMediaPlayer.PSMPInfo infoBeforeCastDisconnection; private volatile PlaybackServiceMediaPlayer.PSMPInfo infoBeforeCastDisconnection;
private boolean mWifiConnectivity = true;
private BroadcastReceiver mWifiBroadcastReceiver;
private static final int NOTIFICATION_ID = 1; private static final int NOTIFICATION_ID = 1;
private PlaybackServiceMediaPlayer mediaPlayer; private PlaybackServiceMediaPlayer mediaPlayer;
@ -318,6 +330,7 @@ public class PlaybackService extends Service implements SharedPreferences.OnShar
unregisterReceiver(pausePlayCurrentEpisodeReceiver); unregisterReceiver(pausePlayCurrentEpisodeReceiver);
unregisterReceiver(pauseResumeCurrentEpisodeReceiver); unregisterReceiver(pauseResumeCurrentEpisodeReceiver);
CastManager.getInstance().removeCastConsumer(castConsumer); CastManager.getInstance().removeCastConsumer(castConsumer);
unregisterWifiBroadcastReceiver();
mediaPlayer.shutdown(); mediaPlayer.shutdown();
taskManager.shutdown(); taskManager.shutdown();
} }
@ -1561,6 +1574,7 @@ public class PlaybackService extends Service implements SharedPreferences.OnShar
(mediaPlayer != null) ? mediaPlayer.getPSMPInfo() : (mediaPlayer != null) ? mediaPlayer.getPSMPInfo() :
new PlaybackServiceMediaPlayer.PSMPInfo(PlayerStatus.STOPPED, null)); new PlaybackServiceMediaPlayer.PSMPInfo(PlayerStatus.STOPPED, null));
sendNotificationBroadcast(NOTIFICATION_TYPE_RELOAD, EXTRA_CODE_CAST); sendNotificationBroadcast(NOTIFICATION_TYPE_RELOAD, EXTRA_CODE_CAST);
registerWifiBroadcastReceiver();
} }
@Override @Override
@ -1602,6 +1616,7 @@ public class PlaybackService extends Service implements SharedPreferences.OnShar
Log.d(TAG, "Cast session disconnected, but no current media"); Log.d(TAG, "Cast session disconnected, but no current media");
sendNotificationBroadcast(NOTIFICATION_TYPE_PLAYBACK_END, 0); sendNotificationBroadcast(NOTIFICATION_TYPE_PLAYBACK_END, 0);
} }
unregisterWifiBroadcastReceiver();
} }
}; };
@ -1620,4 +1635,37 @@ public class PlaybackService extends Service implements SharedPreferences.OnShar
info.playerStatus.isAtLeast(PlayerStatus.PREPARING)); info.playerStatus.isAtLeast(PlayerStatus.PREPARING));
} }
} }
private void registerWifiBroadcastReceiver() {
if (mWifiBroadcastReceiver != null) {
return;
}
mWifiBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
boolean isConnected = info.isConnected();
//apparently this method gets called twice when a change happens, but one run is enough.
if (isConnected && !mWifiConnectivity) {
mWifiConnectivity = true;
CastManager castMgr = CastManager.getInstance();
castMgr.startCastDiscovery();
castMgr.reconnectSessionIfPossible(RECONNECTION_ATTEMPT_PERIOD_S, NetworkUtils.getWifiSsid());
} else {
mWifiConnectivity = isConnected;
}
}
}
};
registerReceiver(mWifiBroadcastReceiver,
new IntentFilter(WifiManager.NETWORK_STATE_CHANGED_ACTION));
}
private void unregisterWifiBroadcastReceiver() {
if (mWifiBroadcastReceiver != null) {
unregisterReceiver(mWifiBroadcastReceiver);
mWifiBroadcastReceiver = null;
}
}
} }

View File

@ -1,6 +1,7 @@
package de.danoeh.antennapod.core.service.playback; package de.danoeh.antennapod.core.service.playback;
import android.content.Context; import android.content.Context;
import android.net.wifi.WifiManager;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.util.Log; import android.util.Log;
import android.util.Pair; import android.util.Pair;
@ -33,6 +34,11 @@ public abstract class PlaybackServiceMediaPlayer {
protected volatile PlayerStatus playerStatus; protected volatile PlayerStatus playerStatus;
/**
* A wifi-lock that is acquired if the media file is being streamed.
*/
private WifiManager.WifiLock wifiLock;
protected final PSMPCallback callback; protected final PSMPCallback callback;
protected final Context context; protected final Context context;
@ -237,6 +243,28 @@ public abstract class PlaybackServiceMediaPlayer {
*/ */
public abstract void stop(); public abstract void stop();
/**
* @return {@code true} if the WifiLock feature should be used, {@code false} otherwise.
*/
protected abstract boolean shouldLockWifi();
protected final synchronized void acquireWifiLockIfNecessary() {
if (shouldLockWifi()) {
if (wifiLock == null) {
wifiLock = ((WifiManager) context.getSystemService(Context.WIFI_SERVICE))
.createWifiLock(WifiManager.WIFI_MODE_FULL, TAG);
wifiLock.setReferenceCounted(false);
}
wifiLock.acquire();
}
}
protected final synchronized void releaseWifiLockIfNecessary() {
if (wifiLock != null && wifiLock.isHeld()) {
wifiLock.release();
}
}
/** /**
* Sets the player status of the PSMP object. PlayerStatus and media attributes have to be set at the same time * Sets the player status of the PSMP object. PlayerStatus and media attributes have to be set at the same time
* so that getPSMPInfo can't return an invalid state (e.g. status is PLAYING, but media is null). * so that getPSMPInfo can't return an invalid state (e.g. status is PLAYING, but media is null).

View File

@ -450,4 +450,9 @@ public class RemotePSMP extends PlaybackServiceMediaPlayer {
public void stop() { public void stop() {
//TODO //TODO
} }
@Override
protected boolean shouldLockWifi() {
return false;
}
} }

View File

@ -92,6 +92,18 @@ public class NetworkUtils {
return mWifi.isConnected(); return mWifi.isConnected();
} }
/**
* Returns the SSID of the wifi connection, or <code>null</code> if there is no wifi.
*/
public static String getWifiSsid() {
WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
if (wifiInfo != null) {
return wifiInfo.getSSID();
}
return null;
}
public static Observable<Long> getFeedMediaSizeObservable(FeedMedia media) { public static Observable<Long> getFeedMediaSizeObservable(FeedMedia media) {
return Observable.create(new Observable.OnSubscribe<Long>() { return Observable.create(new Observable.OnSubscribe<Long>() {
@Override @Override