summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/src/play/java/de/danoeh/antennapod/cast/CustomMRControllerDialog.java139
-rw-r--r--app/src/play/res/layout/media_router_controller.xml6
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java18
3 files changed, 139 insertions, 24 deletions
diff --git a/app/src/play/java/de/danoeh/antennapod/cast/CustomMRControllerDialog.java b/app/src/play/java/de/danoeh/antennapod/cast/CustomMRControllerDialog.java
index 7469e830a..db8c14235 100644
--- a/app/src/play/java/de/danoeh/antennapod/cast/CustomMRControllerDialog.java
+++ b/app/src/play/java/de/danoeh/antennapod/cast/CustomMRControllerDialog.java
@@ -1,29 +1,43 @@
package de.danoeh.antennapod.cast;
+import android.app.PendingIntent;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.AsyncTask;
import android.os.Bundle;
import android.os.RemoteException;
+import android.support.annotation.NonNull;
import android.support.v4.media.MediaDescriptionCompat;
import android.support.v4.media.MediaMetadataCompat;
import android.support.v4.media.session.MediaControllerCompat;
import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat;
+import android.support.v4.view.accessibility.AccessibilityEventCompat;
import android.support.v7.app.MediaRouteControllerDialog;
+import android.support.v7.graphics.Palette;
import android.support.v7.media.MediaRouter;
import android.text.TextUtils;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.request.target.Target;
+
+import java.util.concurrent.ExecutionException;
+
import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.glide.ApGlideSettings;
public class CustomMRControllerDialog extends MediaRouteControllerDialog {
public static final String TAG = "CustomMRContrDialog";
@@ -37,6 +51,10 @@ public class CustomMRControllerDialog extends MediaRouteControllerDialog {
private ImageButton playPauseButton;
private LinearLayout rootView;
+ private boolean viewsCreated = false;
+
+ private FetchArtTask fetchArtTask;
+
private MediaControllerCompat mediaController;
private MediaControllerCompat.Callback mediaControllerCallback;
@@ -87,10 +105,24 @@ public class CustomMRControllerDialog extends MediaRouteControllerDialog {
ViewGroup.LayoutParams.WRAP_CONTENT));
rootView.setOrientation(LinearLayout.VERTICAL);
+ // Start the session activity when a content item (album art, title or subtitle) is clicked.
+ View.OnClickListener onClickListener = v -> {
+ if (mediaController != null) {
+ PendingIntent pi = mediaController.getSessionActivity();
+ if (pi != null) {
+ try {
+ pi.send();
+ dismiss();
+ } catch (PendingIntent.CanceledException e) {
+ Log.e(TAG, pi + " was not sent, it had been canceled.");
+ }
+ }
+ }
+ };
+
artView = new ImageView(getContext()) {
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- int desiredWidth = widthMeasureSpec;
int desiredHeight = heightMeasureSpec;
if (MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.EXACTLY) {
Drawable drawable = getDrawable();
@@ -110,26 +142,53 @@ public class CustomMRControllerDialog extends MediaRouteControllerDialog {
}
}
- super.onMeasure(desiredWidth, desiredHeight);
+ super.onMeasure(widthMeasureSpec, desiredHeight);
}
};
artView.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
artView.setScaleType(ImageView.ScaleType.FIT_CENTER);
+ artView.setOnClickListener(onClickListener);
rootView.addView(artView);
View playbackControlLayout = View.inflate(getContext(), R.layout.media_router_controller, rootView);
titleView = (TextView) playbackControlLayout.findViewById(R.id.mrc_control_title);
subtitleView = (TextView) playbackControlLayout.findViewById(R.id.mrc_control_subtitle);
+ playbackControlLayout.findViewById(R.id.mrc_control_title_container).setOnClickListener(onClickListener);
playPauseButton = (ImageButton) playbackControlLayout.findViewById(R.id.mrc_control_play_pause);
+ playPauseButton.setOnClickListener(v -> {
+ PlaybackStateCompat state;
+ if (mediaController != null && (state = mediaController.getPlaybackState()) != null) {
+ boolean isPlaying = state.getState() == PlaybackStateCompat.STATE_PLAYING;
+ if (isPlaying) {
+ mediaController.getTransportControls().pause();
+ } else {
+ mediaController.getTransportControls().play();
+ }
+ // Announce the action for accessibility.
+ AccessibilityManager accessibilityManager = (AccessibilityManager)
+ getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
+ if (accessibilityManager != null && accessibilityManager.isEnabled()) {
+ AccessibilityEvent event = AccessibilityEvent.obtain(
+ AccessibilityEventCompat.TYPE_ANNOUNCEMENT);
+ event.setPackageName(getContext().getPackageName());
+ event.setClassName(getClass().getName());
+ int resId = isPlaying ?
+ android.support.v7.mediarouter.R.string.mr_controller_pause : android.support.v7.mediarouter.R.string.mr_controller_play;
+ event.getText().add(getContext().getString(resId));
+ accessibilityManager.sendAccessibilityEvent(event);
+ }
+ }
+ });
+ viewsCreated = true;
updateViews();
return rootView;
}
private void updateViews() {
- if (token == null || artView == null || mediaController == null) {
+ if (!viewsCreated || token == null || mediaController == null) {
rootView.setVisibility(View.GONE);
return;
}
@@ -174,19 +233,27 @@ public class CustomMRControllerDialog extends MediaRouteControllerDialog {
showSubtitle = true;
}
}
+ if (showSubtitle) {
+ titleView.setSingleLine();
+ } else {
+ titleView.setMaxLines(2);
+ }
titleView.setVisibility(showTitle ? View.VISIBLE : View.GONE);
subtitleView.setVisibility(showSubtitle ? View.VISIBLE : View.GONE);
updateState();
- Bitmap art = metadata.getBitmap(MediaMetadataCompat.METADATA_KEY_ART);
- if (art == null) {
+ if(rootView.getVisibility() != View.VISIBLE) {
artView.setVisibility(View.GONE);
- return;
+ rootView.setVisibility(View.VISIBLE);
+ }
+
+ if (fetchArtTask != null) {
+ fetchArtTask.cancel(true);
}
- artView.setImageBitmap(art);
- artView.setVisibility(View.VISIBLE);
- rootView.setVisibility(View.VISIBLE);
+
+ fetchArtTask = new FetchArtTask(description);
+ fetchArtTask.execute();
}
private void updateState() {
@@ -223,4 +290,58 @@ public class CustomMRControllerDialog extends MediaRouteControllerDialog {
TypedValue value = new TypedValue();
return context.getTheme().resolveAttribute(attr, value, true) ? value.resourceId : 0;
}
+
+ private class FetchArtTask extends AsyncTask<Void, Void, Bitmap> {
+ final Bitmap iconBitmap;
+ final Uri iconUri;
+ int backgroundColor;
+
+ FetchArtTask(@NonNull MediaDescriptionCompat description) {
+ iconBitmap = description.getIconBitmap();
+ iconUri = description.getIconUri();
+ }
+
+ @Override
+ protected Bitmap doInBackground(Void... arg) {
+ Bitmap art = null;
+ if (iconBitmap != null) {
+ art = iconBitmap;
+ } else if (iconUri != null) {
+ try {
+ art = Glide.with(getContext().getApplicationContext())
+ .load(iconUri.toString())
+ .asBitmap()
+ .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
+ .into(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
+ .get();
+ } catch (InterruptedException | ExecutionException e) {
+ Log.e(TAG, "Image art load failed", e);
+ }
+ }
+ if (art != null && art.getWidth()*9 < art.getHeight()*16) {
+ // Portrait art requires dominant color as background color.
+ Palette palette = new Palette.Builder(art).maximumColorCount(1).generate();
+ backgroundColor = palette.getSwatches().isEmpty()
+ ? 0 : palette.getSwatches().get(0).getRgb();
+ }
+ return art;
+ }
+
+ @Override
+ protected void onCancelled() {
+ fetchArtTask = null;
+ }
+
+ @Override
+ protected void onPostExecute(Bitmap art) {
+ fetchArtTask = null;
+ if (art != null) {
+ artView.setBackgroundColor(backgroundColor);
+ artView.setImageBitmap(art);
+ artView.setVisibility(View.VISIBLE);
+ } else {
+ artView.setVisibility(View.GONE);
+ }
+ }
+ }
}
diff --git a/app/src/play/res/layout/media_router_controller.xml b/app/src/play/res/layout/media_router_controller.xml
index 15c2f9731..a94eb8fa1 100644
--- a/app/src/play/res/layout/media_router_controller.xml
+++ b/app/src/play/res/layout/media_router_controller.xml
@@ -39,12 +39,12 @@
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_toLeftOf="@id/mrc_control_play_pause"
- android:layout_toStartOf="@id/mrc_control_play_pause">
+ android:layout_toStartOf="@id/mrc_control_play_pause"
+ android:layout_centerVertical="true">
<TextView android:id="@+id/mrc_control_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:textAppearance="?attr/mediaRouteControllerPrimaryTextStyle"
- android:singleLine="true" />
+ android:textAppearance="?attr/mediaRouteControllerPrimaryTextStyle"/>
<TextView android:id="@+id/mrc_control_subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java
index c79d662cb..88b2c70de 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java
@@ -939,16 +939,16 @@ public class PlaybackService extends Service {
MediaMetadataCompat.Builder builder = new MediaMetadataCompat.Builder();
builder.putString(MediaMetadataCompat.METADATA_KEY_ARTIST, p.getFeedTitle());
builder.putString(MediaMetadataCompat.METADATA_KEY_TITLE, p.getEpisodeTitle());
+ builder.putString(MediaMetadataCompat.METADATA_KEY_ALBUM, p.getFeedTitle());
builder.putLong(MediaMetadataCompat.METADATA_KEY_DURATION, p.getDuration());
builder.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, p.getEpisodeTitle());
- builder.putString(MediaMetadataCompat.METADATA_KEY_ALBUM, p.getFeedTitle());
+ builder.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_SUBTITLE, p.getFeedTitle());
String imageLocation = p.getImageLocation();
if (!TextUtils.isEmpty(imageLocation)) {
- if (isCasting || UserPreferences.setLockscreenBackground()) {
+ if (UserPreferences.setLockscreenBackground()) {
builder.putString(MediaMetadataCompat.METADATA_KEY_ART_URI, imageLocation);
- builder.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON_URI, imageLocation);
try {
Bitmap art = Glide.with(this)
.load(imageLocation)
@@ -957,18 +957,12 @@ public class PlaybackService extends Service {
.into(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
.get();
builder.putBitmap(MediaMetadataCompat.METADATA_KEY_ART, art);
- // Icon is useful for MediaDescription,
- Bitmap icon = Glide.with(this)
- .load(imageLocation)
- .asBitmap()
- .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
- .fitCenter()
- .into(128, 128)
- .get();
- builder.putBitmap(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON, icon);
} catch (Throwable tr) {
Log.e(TAG, Log.getStackTraceString(tr));
}
+ } else if (isCasting) {
+ // In the absence of metadata art, the controller dialog takes care of creating it.
+ builder.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON_URI, imageLocation);
}
}
if (!Thread.currentThread().isInterrupted() && started) {