package de.danoeh.antennapod.activity; import android.content.SharedPreferences; import android.media.AudioManager; import android.os.Bundle; import android.preference.PreferenceManager; import android.support.annotation.CallSuper; import android.support.v4.view.MenuItemCompat; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import com.google.android.gms.cast.ApplicationMetadata; import de.danoeh.antennapod.R; import de.danoeh.antennapod.core.cast.CastConsumer; import de.danoeh.antennapod.core.cast.CastManager; import de.danoeh.antennapod.core.cast.DefaultCastConsumer; import de.danoeh.antennapod.core.cast.SwitchableMediaRouteActionProvider; import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.service.playback.PlaybackService; /** * Activity that allows for showing the MediaRouter button whenever there's a cast device in the * network. */ public abstract class CastEnabledActivity extends AppCompatActivity implements SharedPreferences.OnSharedPreferenceChangeListener { public static final String TAG = "CastEnabledActivity"; protected CastManager castManager; protected SwitchableMediaRouteActionProvider mediaRouteActionProvider; private final CastButtonVisibilityManager castButtonVisibilityManager = new CastButtonVisibilityManager(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); PreferenceManager.getDefaultSharedPreferences(getApplicationContext()). registerOnSharedPreferenceChangeListener(this); castManager = CastManager.getInstance(); castManager.addCastConsumer(castConsumer); castButtonVisibilityManager.setPrefEnabled(UserPreferences.isCastEnabled()); onCastConnectionChanged(castManager.isConnected()); } @Override protected void onDestroy() { PreferenceManager.getDefaultSharedPreferences(getApplicationContext()) .unregisterOnSharedPreferenceChangeListener(this); castManager.removeCastConsumer(castConsumer); super.onDestroy(); } @Override @CallSuper public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); getMenuInflater().inflate(R.menu.cast_enabled, menu); castButtonVisibilityManager.setMenu(menu); return true; } @Override @CallSuper public boolean onPrepareOptionsMenu(Menu menu) { super.onPrepareOptionsMenu(menu); mediaRouteActionProvider = castManager .addMediaRouterButton(menu.findItem(R.id.media_route_menu_item)); mediaRouteActionProvider.setEnabled(castButtonVisibilityManager.shouldEnable()); return true; } @Override protected void onResume() { super.onResume(); castButtonVisibilityManager.setResumed(true); } @Override protected void onPause() { super.onPause(); castButtonVisibilityManager.setResumed(false); } @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { if (UserPreferences.PREF_CAST_ENABLED.equals(key)) { boolean newValue = UserPreferences.isCastEnabled(); Log.d(TAG, "onSharedPreferenceChanged(), isCastEnabled set to " + newValue); castButtonVisibilityManager.setPrefEnabled(newValue); // PlaybackService has its own listener, so if it's active we don't have to take action here. if (!newValue && !PlaybackService.isRunning) { CastManager.getInstance().disconnect(); } } } CastConsumer castConsumer = new DefaultCastConsumer() { @Override public void onApplicationConnected(ApplicationMetadata appMetadata, String sessionId, boolean wasLaunched) { onCastConnectionChanged(true); } @Override public void onDisconnected() { onCastConnectionChanged(false); } }; private void onCastConnectionChanged(boolean connected) { if (connected) { castButtonVisibilityManager.onConnected(); setVolumeControlStream(AudioManager.USE_DEFAULT_STREAM_TYPE); } else { castButtonVisibilityManager.onDisconnected(); setVolumeControlStream(AudioManager.STREAM_MUSIC); } } /** * Should be called by any activity or fragment for which the cast button should be shown. * * @param showAsAction refer to {@link MenuItem#setShowAsAction(int)} */ public final void requestCastButton(int showAsAction) { castButtonVisibilityManager.requestCastButton(showAsAction); } private class CastButtonVisibilityManager { private volatile boolean prefEnabled = false; private volatile boolean viewRequested = false; private volatile boolean resumed = false; private volatile boolean connected = false; private volatile int showAsAction = MenuItem.SHOW_AS_ACTION_IF_ROOM; private Menu menu; public synchronized void setPrefEnabled(boolean newValue) { if (prefEnabled != newValue && resumed && (viewRequested || connected)) { if (newValue) { castManager.incrementUiCounter(); } else { castManager.decrementUiCounter(); } } prefEnabled = newValue; if (mediaRouteActionProvider != null) { mediaRouteActionProvider.setEnabled(prefEnabled && (viewRequested || connected)); } } public synchronized void setResumed(boolean newValue) { if (resumed == newValue) { Log.e(TAG, "resumed should never change to the same value"); return; } resumed = newValue; if (prefEnabled && (viewRequested || connected)) { if (resumed) { castManager.incrementUiCounter(); } else { castManager.decrementUiCounter(); } } } public synchronized void setViewRequested(boolean newValue) { if (viewRequested != newValue && resumed && prefEnabled && !connected) { if (newValue) { castManager.incrementUiCounter(); } else { castManager.decrementUiCounter(); } } viewRequested = newValue; if (mediaRouteActionProvider != null) { mediaRouteActionProvider.setEnabled(prefEnabled && (viewRequested || connected)); } } public synchronized void setConnected(boolean newValue) { if (connected != newValue && resumed && prefEnabled && !prefEnabled) { if (newValue) { castManager.incrementUiCounter(); } else { castManager.decrementUiCounter(); } } connected = newValue; if (mediaRouteActionProvider != null) { mediaRouteActionProvider.setEnabled(prefEnabled && (viewRequested || connected)); } } public synchronized boolean shouldEnable() { return prefEnabled && viewRequested; } public void setMenu(Menu menu) { setViewRequested(false); showAsAction = MenuItem.SHOW_AS_ACTION_IF_ROOM; this.menu = menu; setShowAsAction(); } public void requestCastButton(int showAsAction) { setViewRequested(true); this.showAsAction = showAsAction; setShowAsAction(); } public void onConnected() { setConnected(true); setShowAsAction(); } public void onDisconnected() { setConnected(false); setShowAsAction(); } private void setShowAsAction() { if (menu == null) { Log.d(TAG, "setShowAsAction() without a menu"); return; } MenuItem item = menu.findItem(R.id.media_route_menu_item); if (item == null) { Log.e(TAG, "setShowAsAction(), but cast button not inflated"); return; } MenuItemCompat.setShowAsAction(item, connected? MenuItem.SHOW_AS_ACTION_ALWAYS : showAsAction); } } }