allow fine control on where to show the cast button
This commit is contained in:
parent
a7848f0576
commit
1a33830991
@ -4,16 +4,19 @@ 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.DefaultCastConsumer;
|
||||
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;
|
||||
@ -27,10 +30,8 @@ public abstract class CastEnabledActivity extends AppCompatActivity
|
||||
public static final String TAG = "CastEnabledActivity";
|
||||
|
||||
protected CastManager castManager;
|
||||
private final Object UI_COUNTER_LOCK = new Object();
|
||||
private volatile boolean isResumed = false;
|
||||
protected SwitchableMediaRouteActionProvider mediaRouteActionProvider;
|
||||
protected volatile boolean isCastEnabled = false;
|
||||
private final CastButtonVisibilityManager castButtonVisibilityManager = new CastButtonVisibilityManager();
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
@ -41,7 +42,7 @@ public abstract class CastEnabledActivity extends AppCompatActivity
|
||||
|
||||
castManager = CastManager.getInstance();
|
||||
castManager.addCastConsumer(castConsumer);
|
||||
isCastEnabled = UserPreferences.isCastEnabled();
|
||||
castButtonVisibilityManager.setPrefEnabled(UserPreferences.isCastEnabled());
|
||||
onCastConnectionChanged(castManager.isConnected());
|
||||
}
|
||||
|
||||
@ -54,41 +55,34 @@ public abstract class CastEnabledActivity extends AppCompatActivity
|
||||
}
|
||||
|
||||
@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(isCastEnabled);
|
||||
mediaRouteActionProvider.setEnabled(castButtonVisibilityManager.shouldEnable());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
synchronized (UI_COUNTER_LOCK) {
|
||||
isResumed = true;
|
||||
if (isCastEnabled) {
|
||||
castManager.incrementUiCounter();
|
||||
}
|
||||
}
|
||||
castButtonVisibilityManager.setResumed(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
synchronized (UI_COUNTER_LOCK) {
|
||||
isResumed = false;
|
||||
if (isCastEnabled) {
|
||||
castManager.decrementUiCounter();
|
||||
}
|
||||
}
|
||||
castButtonVisibilityManager.setResumed(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -96,19 +90,9 @@ public abstract class CastEnabledActivity extends AppCompatActivity
|
||||
if (UserPreferences.PREF_CAST_ENABLED.equals(key)) {
|
||||
boolean newValue = UserPreferences.isCastEnabled();
|
||||
Log.d(TAG, "onSharedPreferenceChanged(), isCastEnabled set to " + newValue);
|
||||
synchronized (UI_COUNTER_LOCK) {
|
||||
if (isCastEnabled != newValue && isResumed) {
|
||||
if (newValue) {
|
||||
castManager.incrementUiCounter();
|
||||
} else {
|
||||
castManager.decrementUiCounter();
|
||||
}
|
||||
}
|
||||
isCastEnabled = newValue;
|
||||
}
|
||||
mediaRouteActionProvider.setEnabled(isCastEnabled);
|
||||
castButtonVisibilityManager.setPrefEnabled(newValue);
|
||||
// PlaybackService has its own listener, so if it's active we don't have to take action here.
|
||||
if (!isCastEnabled && !PlaybackService.isRunning) {
|
||||
if (!newValue && !PlaybackService.isRunning) {
|
||||
CastManager.getInstance().disconnect();
|
||||
}
|
||||
}
|
||||
@ -133,4 +117,86 @@ public abstract class CastEnabledActivity extends AppCompatActivity
|
||||
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 Menu menu;
|
||||
|
||||
public synchronized void setPrefEnabled(boolean newValue) {
|
||||
if (prefEnabled != newValue && resumed && viewRequested) {
|
||||
if (newValue) {
|
||||
castManager.incrementUiCounter();
|
||||
} else {
|
||||
castManager.decrementUiCounter();
|
||||
}
|
||||
}
|
||||
prefEnabled = newValue;
|
||||
if (mediaRouteActionProvider != null) {
|
||||
mediaRouteActionProvider.setEnabled(prefEnabled && viewRequested);
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
if (resumed) {
|
||||
castManager.incrementUiCounter();
|
||||
} else {
|
||||
castManager.decrementUiCounter();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void setViewRequested(boolean newValue) {
|
||||
if (viewRequested != newValue && resumed && prefEnabled) {
|
||||
if (newValue) {
|
||||
castManager.incrementUiCounter();
|
||||
} else {
|
||||
castManager.decrementUiCounter();
|
||||
}
|
||||
}
|
||||
viewRequested = newValue;
|
||||
if (mediaRouteActionProvider != null) {
|
||||
mediaRouteActionProvider.setEnabled(prefEnabled && viewRequested);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized boolean shouldEnable() {
|
||||
return prefEnabled && viewRequested;
|
||||
}
|
||||
|
||||
public void setMenu(Menu menu) {
|
||||
setViewRequested(false);
|
||||
this.menu = menu;
|
||||
}
|
||||
|
||||
public void requestCastButton(int showAsAction) {
|
||||
setViewRequested(true);
|
||||
if (menu == null) {
|
||||
Log.e(TAG, "Cast button requested without a menu");
|
||||
return;
|
||||
}
|
||||
MenuItem item = menu.findItem(R.id.media_route_menu_item);
|
||||
if (item == null) {
|
||||
Log.e(TAG, "Cast button requested, but not inflated");
|
||||
return;
|
||||
}
|
||||
MenuItemCompat.setShowAsAction(menu.findItem(R.id.media_route_menu_item), showAsAction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ import android.support.v7.widget.Toolbar;
|
||||
import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
@ -503,6 +504,26 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi
|
||||
Glide.get(this).clearMemory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
boolean retVal = super.onCreateOptionsMenu(menu);
|
||||
switch (getLastNavFragment()) {
|
||||
case QueueFragment.TAG:
|
||||
case EpisodesFragment.TAG:
|
||||
requestCastButton(MenuItem.SHOW_AS_ACTION_IF_ROOM);
|
||||
return retVal;
|
||||
case DownloadsFragment.TAG:
|
||||
case PlaybackHistoryFragment.TAG:
|
||||
case AddFeedFragment.TAG:
|
||||
case SubscriptionFragment.TAG:
|
||||
return retVal;
|
||||
default:
|
||||
requestCastButton(MenuItem.SHOW_AS_ACTION_NEVER);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
if (drawerToggle.onOptionsItemSelected(item)) {
|
||||
|
@ -281,6 +281,7 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
super.onCreateOptionsMenu(menu);
|
||||
requestCastButton(MenuItem.SHOW_AS_ACTION_ALWAYS);
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
inflater.inflate(R.menu.mediaplayer, menu);
|
||||
return true;
|
||||
|
@ -39,6 +39,7 @@ import org.apache.commons.lang3.ArrayUtils;
|
||||
import java.util.List;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.activity.CastEnabledActivity;
|
||||
import de.danoeh.antennapod.activity.MainActivity;
|
||||
import de.danoeh.antennapod.adapter.DefaultActionButtonCallback;
|
||||
import de.danoeh.antennapod.core.event.DownloadEvent;
|
||||
@ -311,6 +312,7 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
|
||||
if(!isAdded() || item == null) {
|
||||
return;
|
||||
}
|
||||
((CastEnabledActivity) getActivity()).requestCastButton(MenuItem.SHOW_AS_ACTION_ALWAYS);
|
||||
inflater.inflate(R.menu.feeditem_options, menu);
|
||||
popupMenu = menu;
|
||||
if (item.hasMedia()) {
|
||||
|
@ -5,7 +5,6 @@
|
||||
<item
|
||||
android:id="@+id/media_route_menu_item"
|
||||
android:title="@string/cast_media_route_menu_title"
|
||||
android:enabled="false"
|
||||
custom:actionProviderClass="de.danoeh.antennapod.core.cast.SwitchableMediaRouteActionProvider"
|
||||
custom:showAsAction="always"/>
|
||||
custom:showAsAction="ifRoom"/>
|
||||
</menu>
|
@ -1,7 +1,15 @@
|
||||
package de.danoeh.antennapod.core.cast;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.ContextWrapper;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v7.app.MediaRouteActionProvider;
|
||||
import android.support.v7.app.MediaRouteChooserDialogFragment;
|
||||
import android.support.v7.app.MediaRouteControllerDialogFragment;
|
||||
import android.support.v7.media.MediaRouter;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* <p>Action Provider that extends {@link MediaRouteActionProvider} and allows the client to
|
||||
@ -11,7 +19,12 @@ import android.support.v7.app.MediaRouteActionProvider;
|
||||
* <code>setEnabled(true)</code>.</p>
|
||||
*/
|
||||
public class SwitchableMediaRouteActionProvider extends MediaRouteActionProvider {
|
||||
public static final String TAG = "SwitchblMediaRtActProv";
|
||||
|
||||
private static final String CHOOSER_FRAGMENT_TAG =
|
||||
"android.support.v7.mediarouter:MediaRouteChooserDialogFragment";
|
||||
private static final String CONTROLLER_FRAGMENT_TAG =
|
||||
"android.support.v7.mediarouter:MediaRouteControllerDialogFragment";
|
||||
private boolean enabled;
|
||||
|
||||
public SwitchableMediaRouteActionProvider(Context context) {
|
||||
@ -33,4 +46,61 @@ public class SwitchableMediaRouteActionProvider extends MediaRouteActionProvider
|
||||
public boolean isVisible() {
|
||||
return enabled && super.isVisible();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPerformDefaultAction() {
|
||||
if (!super.onPerformDefaultAction()) {
|
||||
// there is no button, but we should still show the dialog if it's the case.
|
||||
if (!isVisible()) {
|
||||
return false;
|
||||
}
|
||||
FragmentManager fm = getFragmentManager();
|
||||
if (fm == null) {
|
||||
return false;
|
||||
}
|
||||
MediaRouter.RouteInfo route = MediaRouter.getInstance(getContext()).getSelectedRoute();
|
||||
if (route.isDefault() || !route.matchesSelector(getRouteSelector())) {
|
||||
if (fm.findFragmentByTag(CHOOSER_FRAGMENT_TAG) != null) {
|
||||
Log.w(TAG, "showDialog(): Route chooser dialog already showing!");
|
||||
return false;
|
||||
}
|
||||
MediaRouteChooserDialogFragment f =
|
||||
getDialogFactory().onCreateChooserDialogFragment();
|
||||
f.setRouteSelector(getRouteSelector());
|
||||
f.show(fm, CHOOSER_FRAGMENT_TAG);
|
||||
} else {
|
||||
if (fm.findFragmentByTag(CONTROLLER_FRAGMENT_TAG) != null) {
|
||||
Log.w(TAG, "showDialog(): Route controller dialog already showing!");
|
||||
return false;
|
||||
}
|
||||
MediaRouteControllerDialogFragment f =
|
||||
getDialogFactory().onCreateControllerDialogFragment();
|
||||
f.show(fm, CONTROLLER_FRAGMENT_TAG);
|
||||
}
|
||||
return true;
|
||||
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private FragmentManager getFragmentManager() {
|
||||
Activity activity = getActivity();
|
||||
if (activity instanceof FragmentActivity) {
|
||||
return ((FragmentActivity)activity).getSupportFragmentManager();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Activity getActivity() {
|
||||
// Gross way of unwrapping the Activity so we can get the FragmentManager
|
||||
Context context = getContext();
|
||||
while (context instanceof ContextWrapper) {
|
||||
if (context instanceof Activity) {
|
||||
return (Activity)context;
|
||||
}
|
||||
context = ((ContextWrapper)context).getBaseContext();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user