diff --git a/app/src/main/java/org/schabi/newpipe/ActionBarHandler.java b/app/src/main/java/org/schabi/newpipe/ActionBarHandler.java index 76955d824..23ae0724d 100644 --- a/app/src/main/java/org/schabi/newpipe/ActionBarHandler.java +++ b/app/src/main/java/org/schabi/newpipe/ActionBarHandler.java @@ -3,6 +3,7 @@ package org.schabi.newpipe; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; +import android.graphics.Bitmap; import android.net.Uri; import android.os.Bundle; import android.preference.PreferenceManager; @@ -40,7 +41,10 @@ class ActionBarHandler { private static final String TAG = ActionBarHandler.class.toString(); private static final String KORE_PACKET = "org.xbmc.kore"; + private int serviceId; private String websiteUrl = ""; + private Bitmap videoThumbnail = null; + private String channelName = ""; private AppCompatActivity activity; private VideoInfo.VideoStream[] videoStreams = null; private VideoInfo.AudioStream audioStream = null; @@ -73,6 +77,18 @@ class ActionBarHandler { } } + public void setServiceId(int id) { + serviceId = id; + } + + public void setSetVideoThumbnail(Bitmap bitmap) { + videoThumbnail = bitmap; + } + + public void setChannelName(String name) { + channelName = name; + } + @SuppressWarnings("deprecation") public void setStreams(VideoInfo.VideoStream[] videoStreams, VideoInfo.AudioStream[] audioStreams) { this.videoStreams = videoStreams; @@ -143,37 +159,41 @@ class ActionBarHandler { } public boolean onItemSelected(MenuItem item) { - int id = item.getItemId(); - switch(id) { - case R.id.menu_item_share: - if(!videoTitle.isEmpty()) { + if(!videoTitle.isEmpty()) { + int id = item.getItemId(); + switch (id) { + case R.id.menu_item_share: { Intent intent = new Intent(); intent.setAction(Intent.ACTION_SEND); intent.putExtra(Intent.EXTRA_TEXT, websiteUrl); intent.setType("text/plain"); activity.startActivity(Intent.createChooser(intent, activity.getString(R.string.shareDialogTitle))); + return true; + } + case R.id.menu_item_openInBrowser: { + openInBrowser(); } return true; - case R.id.menu_item_openInBrowser: { - openInBrowser(); + case R.id.menu_item_download: + downloadVideo(); + return true; + case R.id.action_settings: { + Intent intent = new Intent(activity, SettingsActivity.class); + activity.startActivity(intent); + } + break; + case R.id.action_play_with_kodi: + playWithKodi(); + return true; + case R.id.menu_item_play_audio: + playAudio(); + return true; + default: + Log.e(TAG, "Menu Item not known"); } - return true; - case R.id.menu_item_download: - downloadVideo(); - return true; - case R.id.action_settings: { - Intent intent = new Intent(activity, SettingsActivity.class); - activity.startActivity(intent); - } - break; - case R.id.action_play_with_kodi: - playWithKodi(); - return true; - case R.id.menu_item_play_audio: - playAudio(); - return true; - default: - Log.e(TAG, "Menu Item not known"); + } else { + // That line may not be necessary. + return true; } return false; } @@ -302,18 +322,24 @@ class ActionBarHandler { .getBoolean(activity.getString(R.string.useExternalAudioPlayer), false); Intent intent; - if (!externalAudioPlayer && android.os.Build.VERSION.SDK_INT >= 18)//internal music player: explicit intent - { - intent = new Intent(activity, BackgroundPlayer.class); + if (!externalAudioPlayer && android.os.Build.VERSION.SDK_INT >= 18) { + //internal music player: explicit intent + if (!BackgroundPlayer.isRunning && videoThumbnail != null) { + ActivityCommunicator.getCommunicator() + .backgroundPlayerThumbnail = videoThumbnail; + intent = new Intent(activity, BackgroundPlayer.class); - intent.setAction(Intent.ACTION_VIEW); - Log.i(TAG, "audioStream is null:" + (audioStream == null)); - Log.i(TAG, "audioStream.url is null:"+(audioStream.url==null)); - intent.setDataAndType(Uri.parse(audioStream.url), - MediaFormat.getMimeById(audioStream.format)); - intent.putExtra(Intent.EXTRA_TITLE, videoTitle); - intent.putExtra("title", videoTitle); - activity.startService(intent); + intent.setAction(Intent.ACTION_VIEW); + Log.i(TAG, "audioStream is null:" + (audioStream == null)); + Log.i(TAG, "audioStream.url is null:" + (audioStream.url == null)); + intent.setDataAndType(Uri.parse(audioStream.url), + MediaFormat.getMimeById(audioStream.format)); + intent.putExtra(BackgroundPlayer.TITLE, videoTitle); + intent.putExtra(BackgroundPlayer.WEB_URL, websiteUrl); + intent.putExtra(BackgroundPlayer.SERVICE_ID, serviceId); + intent.putExtra(BackgroundPlayer.CHANNEL_NAME, channelName); + activity.startService(intent); + } } else { intent = new Intent(); try { diff --git a/app/src/main/java/org/schabi/newpipe/ActivityCommunicator.java b/app/src/main/java/org/schabi/newpipe/ActivityCommunicator.java new file mode 100644 index 000000000..b09652a6c --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/ActivityCommunicator.java @@ -0,0 +1,42 @@ +package org.schabi.newpipe; + +/** + * Created by Christian Schabesberger on 24.12.15. + * + * Copyright (C) Christian Schabesberger 2015 + * ActivityCommunicator.java is part of NewPipe. + * + * NewPipe is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NewPipe is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NewPipe. If not, see . + */ + +import android.graphics.Bitmap; + +/** + * Singleton: + * Used to send data between certain Activity/Services within the same process. + * This can be considered as hack inside the Android universe. **/ +public class ActivityCommunicator { + + private static ActivityCommunicator activityCommunicator = null; + + public static ActivityCommunicator getCommunicator() { + if(activityCommunicator == null) { + activityCommunicator = new ActivityCommunicator(); + } + return activityCommunicator; + } + + // Thumbnail send from VideoItemDetailFragment to BackgroundPlayer + public volatile Bitmap backgroundPlayerThumbnail; +} diff --git a/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java b/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java index dfea0f1c3..5573e2771 100644 --- a/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java @@ -8,6 +8,8 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.res.Resources; +import android.graphics.Bitmap; import android.media.AudioManager; import android.media.MediaPlayer; import android.net.wifi.WifiManager; @@ -43,8 +45,22 @@ import java.io.IOException; public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPreparedListener*/ { private static final String TAG = BackgroundPlayer.class.toString(); - private static final String ACTION_STOP = TAG+".STOP"; - private static final String ACTION_PLAYPAUSE = TAG+".PLAYPAUSE"; + private static final String ACTION_STOP = TAG + ".STOP"; + private static final String ACTION_PLAYPAUSE = TAG + ".PLAYPAUSE"; + + // Extra intent arguments + public static final String TITLE = "title"; + public static final String WEB_URL = "web_url"; + public static final String SERVICE_ID = "service_id"; + public static final String CHANNEL_NAME="channel_name"; + + private volatile String webUrl = ""; + private volatile int serviceId = -1; + private volatile String channelName = ""; + + // Determines if the service is already running. + // Prevents launching the service twice. + public static volatile boolean isRunning = false; public BackgroundPlayer() { super(); @@ -58,16 +74,22 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare } @Override public int onStartCommand(Intent intent, int flags, int startId) { - Toast.makeText(this, "Playing in background", Toast.LENGTH_SHORT).show();//todo:translation string + Toast.makeText(this, R.string.backgroundPlayerStartPlayingToast, + Toast.LENGTH_SHORT).show(); String source = intent.getDataString(); //Log.i(TAG, "backgroundPLayer source:"+source); - String videoTitle = intent.getStringExtra("title"); + String videoTitle = intent.getStringExtra(TITLE); + webUrl = intent.getStringExtra(WEB_URL); + serviceId = intent.getIntExtra(SERVICE_ID, -1); + channelName = intent.getStringExtra(CHANNEL_NAME); //do nearly everything in a separate thread PlayerThread player = new PlayerThread(source, videoTitle, this); player.start(); + isRunning = true; + // If we get killed after returning here, don't restart return START_NOT_STICKY; } @@ -81,6 +103,7 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare @Override public void onDestroy() { //Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show(); + isRunning = false; } private class PlayerThread extends Thread { @@ -92,6 +115,7 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare private NotificationManager noteMgr; private NotificationCompat.Builder noteBuilder; private WifiManager.WifiLock wifiLock; + private Bitmap videoThumbnail = null; public PlayerThread(String src, String title, BackgroundPlayer owner) { this.source = src; @@ -102,11 +126,14 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare } @Override public void run() { + Resources res = getApplicationContext().getResources(); + mediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);//cpu lock try { mediaPlayer.setDataSource(source); - mediaPlayer.prepare(); //We are already in a separate worker thread, + //We are already in a separate worker thread, //so calling the blocking prepare() method should be ok + mediaPlayer.prepare(); //alternatively: //mediaPlayer.setOnPreparedListener(this); @@ -119,10 +146,18 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare return; } + try { + videoThumbnail = ActivityCommunicator.getCommunicator().backgroundPlayerThumbnail; + } catch (Exception e) { + Log.e(TAG, "Could not get video thumbnail from ActivityCommunicator"); + e.printStackTrace(); + } + WifiManager wifiMgr = ((WifiManager)getSystemService(Context.WIFI_SERVICE)); wifiLock = wifiMgr.createWifiLock(WifiManager.WIFI_MODE_FULL, TAG); - mediaPlayer.setOnCompletionListener(new EndListener(wifiLock));//listen for end of video + //listen for end of video + mediaPlayer.setOnCompletionListener(new EndListener(wifiLock)); //get audio focus /* @@ -142,43 +177,65 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare filter.addAction(ACTION_STOP); registerReceiver(broadcastReceiver, filter); - PendingIntent playPI = PendingIntent.getBroadcast(owner, noteID, new Intent(ACTION_PLAYPAUSE), PendingIntent.FLAG_UPDATE_CURRENT); + PendingIntent playPI = PendingIntent.getBroadcast(owner, noteID, + new Intent(ACTION_PLAYPAUSE), PendingIntent.FLAG_UPDATE_CURRENT); NotificationCompat.Action playButton = new NotificationCompat.Action.Builder (R.drawable.ic_play_arrow_white_48dp, "Play", playPI).build(); + /* NotificationCompat.Action pauseButton = new NotificationCompat.Action.Builder - (R.drawable.ic_play_arrow_white_48dp, "Pause", playPI).build(); + (R.drawable.ic_pause_white_24dp, "Pause", playPI).build(); + */ PendingIntent stopPI = PendingIntent.getBroadcast(owner, noteID, new Intent(ACTION_STOP), PendingIntent.FLAG_UPDATE_CURRENT); - //todo: make it so that tapping the notification brings you back to the Video's DetailActivity - //using setContentIntent noteBuilder = new NotificationCompat.Builder(owner); noteBuilder - .setPriority(Notification.PRIORITY_LOW) - .setCategory(Notification.CATEGORY_TRANSPORT) .setContentTitle(title) - .setContentText("NewPipe is playing in the background")//todo: translation string + //really? Id like to put something more helpful here. + //.setContentText("NewPipe is playing in the background") + .setContentText(channelName) //.setAutoCancel(!mediaPlayer.isPlaying()) .setOngoing(true) .setDeleteIntent(stopPI) - //.setProgress(vidLength, 0, false) //doesn't fit with Notification.MediaStyle - .setSmallIcon(R.mipmap.ic_launcher) - .setTicker(title + " - NewPipe") + //doesn't fit with Notification.MediaStyle + //.setProgress(vidLength, 0, false) + .setSmallIcon(R.drawable.ic_play_circle_filled_white_24dp) + .setLargeIcon(videoThumbnail) + .setTicker( + String.format(res.getString( + R.string.backgroundPlayerTickerText), title)) .addAction(playButton); -/* .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) - .setLargeIcon(cover)*/ + //.setVisibility(NotificationCompat.VISIBILITY_PUBLIC) + //.setLargeIcon(cover) + if(android.os.Build.VERSION.SDK_INT >= 16) + noteBuilder.setPriority(Notification.PRIORITY_LOW); + if(android.os.Build.VERSION.SDK_INT >= 21) + noteBuilder.setCategory(Notification.CATEGORY_TRANSPORT); - noteBuilder.setStyle(new NotificationCompat.MediaStyle() - //.setMediaSession(mMediaSession.getSessionToken()) - .setShowActionsInCompactView(new int[] {0}) - .setShowCancelButton(true) - .setCancelButtonIntent(stopPI) - ); + noteBuilder.setStyle(new NotificationCompat.MediaStyle() + //.setMediaSession(mMediaSession.getSessionToken()) + .setShowActionsInCompactView(new int[]{0}) + .setShowCancelButton(true) + .setCancelButtonIntent(stopPI)); + if(videoThumbnail != null) { + noteBuilder.setLargeIcon(videoThumbnail); + } - startForeground(noteID, noteBuilder.build()); + Notification note = noteBuilder.build(); + + Intent openDetailView = new Intent(getApplicationContext(), + VideoItemDetailActivity.class); + openDetailView.putExtra(VideoItemDetailFragment.STREAMING_SERVICE, serviceId); + openDetailView.putExtra(VideoItemDetailFragment.VIDEO_URL, webUrl); + openDetailView.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + note.contentIntent = PendingIntent.getActivity(getApplicationContext(), + noteID, openDetailView, + PendingIntent.FLAG_UPDATE_CURRENT); + + startForeground(noteID, note); //currently decommissioned progressbar looping update code - works, but doesn't fit inside //Notification.MediaStyle Notification layout. @@ -202,7 +259,7 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); - Log.i(TAG, "received broadcast action:"+action); + //Log.i(TAG, "received broadcast action:"+action); if(action.equals(ACTION_PLAYPAUSE)) { if(mediaPlayer.isPlaying()) { mediaPlayer.pause(); @@ -214,7 +271,8 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare } } else if(action.equals(ACTION_STOP)) { - mediaPlayer.stop();//this auto-releases CPU lock + //this auto-releases CPU lock + mediaPlayer.stop(); afterPlayCleanup(); } } diff --git a/app/src/main/java/org/schabi/newpipe/VideoItemDetailFragment.java b/app/src/main/java/org/schabi/newpipe/VideoItemDetailFragment.java index 4290e5c9c..d1e3d10be 100644 --- a/app/src/main/java/org/schabi/newpipe/VideoItemDetailFragment.java +++ b/app/src/main/java/org/schabi/newpipe/VideoItemDetailFragment.java @@ -73,7 +73,7 @@ public class VideoItemDetailFragment extends Fragment { * The fragment argument representing the item ID that this fragment * represents. */ - public static final String ARG_ITEM_ID = "item_id"; + //public static final String ARG_ITEM_ID = "item_id"; public static final String VIDEO_URL = "video_url"; public static final String STREAMING_SERVICE = "streaming_service"; public static final String AUTO_PLAY = "auto_play"; @@ -81,6 +81,8 @@ public class VideoItemDetailFragment extends Fragment { private AppCompatActivity activity; private ActionBarHandler actionBarHandler; + private int streamingServiceId = -1; + private boolean autoPlayEnabled = false; private VideoInfo currentVideoInfo = null; private boolean showNextVideoItem = false; @@ -105,6 +107,7 @@ public class VideoItemDetailFragment extends Fragment { this.service = service; this.videoUrl = videoUrl; } + @Override public void run() { try { @@ -176,6 +179,7 @@ public class VideoItemDetailFragment extends Fragment { switch (id) { case SetThumbnailRunnable.VIDEO_THUMBNAIL: thumbnailView = (ImageView) a.findViewById(R.id.detailThumbnailView); + actionBarHandler.setSetVideoThumbnail(thumbnail); break; case SetThumbnailRunnable.CHANNEL_THUMBNAIL: thumbnailView = (ImageView) a.findViewById(R.id.detailUploaderThumbnailView); @@ -238,6 +242,7 @@ public class VideoItemDetailFragment extends Fragment { case VideoInfo.VIDEO_AVAILABLE: { videoTitleView.setText(info.title); uploaderView.setText(info.uploader); + actionBarHandler.setChannelName(info.uploader); Locale locale = getPreferredLocale(); NumberFormat nf = NumberFormat.getInstance(locale); @@ -266,6 +271,7 @@ public class VideoItemDetailFragment extends Fragment { descriptionView.setText(Html.fromHtml(info.description)); descriptionView.setMovementMethod(LinkMovementMethod.getInstance()); + actionBarHandler.setServiceId(streamingServiceId); actionBarHandler.setVideoInfo(info.webpage_url, info.title); actionBarHandler.setStartPosition(info.startPosition); @@ -288,12 +294,12 @@ public class VideoItemDetailFragment extends Fragment { public void onClick(View v) { Intent detailIntent = new Intent(getActivity(), VideoItemDetailActivity.class); - detailIntent.putExtra( - VideoItemDetailFragment.ARG_ITEM_ID, currentVideoInfo.nextVideo.id); + /*detailIntent.putExtra( + VideoItemDetailFragment.ARG_ITEM_ID, currentVideoInfo.nextVideo.id); */ detailIntent.putExtra( VideoItemDetailFragment.VIDEO_URL, currentVideoInfo.nextVideo.webpage_url); //todo: make id dynamic the following line is crap - detailIntent.putExtra(VideoItemDetailFragment.STREAMING_SERVICE, 0); + detailIntent.putExtra(VideoItemDetailFragment.STREAMING_SERVICE, streamingServiceId); startActivity(detailIntent); } }); @@ -369,8 +375,8 @@ public class VideoItemDetailFragment extends Fragment { // Otherwise the applications would crash. if(playVideoButton != null) { try { - StreamingService streamingService = ServiceList.getService( - getArguments().getInt(STREAMING_SERVICE)); + streamingServiceId = getArguments().getInt(STREAMING_SERVICE); + StreamingService streamingService = ServiceList.getService(streamingServiceId); Thread videoExtractorThread = new Thread(new VideoExtractorRunnable( getArguments().getString(VIDEO_URL), streamingService)); diff --git a/app/src/main/java/org/schabi/newpipe/VideoItemListActivity.java b/app/src/main/java/org/schabi/newpipe/VideoItemListActivity.java index 37bf67333..6aaf10d41 100644 --- a/app/src/main/java/org/schabi/newpipe/VideoItemListActivity.java +++ b/app/src/main/java/org/schabi/newpipe/VideoItemListActivity.java @@ -190,7 +190,7 @@ public class VideoItemListActivity extends AppCompatActivity // adding or replacing the detail fragment using a // fragment transaction. Bundle arguments = new Bundle(); - arguments.putString(VideoItemDetailFragment.ARG_ITEM_ID, id); + //arguments.putString(VideoItemDetailFragment.ARG_ITEM_ID, id); arguments.putString(VideoItemDetailFragment.VIDEO_URL, webpage_url); arguments.putInt(VideoItemDetailFragment.STREAMING_SERVICE, currentStreamingServiceId); videoFragment = new VideoItemDetailFragment(); @@ -209,7 +209,7 @@ public class VideoItemListActivity extends AppCompatActivity // In single-pane mode, simply start the detail activity // for the selected item ID. Intent detailIntent = new Intent(this, VideoItemDetailActivity.class); - detailIntent.putExtra(VideoItemDetailFragment.ARG_ITEM_ID, id); + //detailIntent.putExtra(VideoItemDetailFragment.ARG_ITEM_ID, id); detailIntent.putExtra(VideoItemDetailFragment.VIDEO_URL, webpage_url); detailIntent.putExtra(VideoItemDetailFragment.STREAMING_SERVICE, currentStreamingServiceId); startActivity(detailIntent); diff --git a/app/src/main/res/drawable-hdpi/ic_pause_white_24dp.png b/app/src/main/res/drawable-hdpi/ic_pause_white_24dp.png new file mode 100644 index 000000000..4d2ea05c4 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_pause_white_24dp.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_play_circle_filled_white_24dp.png b/app/src/main/res/drawable-hdpi/ic_play_circle_filled_white_24dp.png new file mode 100644 index 000000000..f8c7bc9f8 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_play_circle_filled_white_24dp.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_pause_white_24dp.png b/app/src/main/res/drawable-mdpi/ic_pause_white_24dp.png new file mode 100644 index 000000000..2272d478c Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_pause_white_24dp.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_play_circle_filled_white_24dp.png b/app/src/main/res/drawable-mdpi/ic_play_circle_filled_white_24dp.png new file mode 100644 index 000000000..9681bf5a5 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_play_circle_filled_white_24dp.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_pause_white_24dp.png b/app/src/main/res/drawable-xhdpi/ic_pause_white_24dp.png new file mode 100644 index 000000000..f49aed757 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_pause_white_24dp.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_play_circle_filled_white_24dp.png b/app/src/main/res/drawable-xhdpi/ic_play_circle_filled_white_24dp.png new file mode 100644 index 000000000..5dcdf0d7a Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_play_circle_filled_white_24dp.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_pause_white_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_pause_white_24dp.png new file mode 100644 index 000000000..7192ad487 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_pause_white_24dp.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_play_circle_filled_white_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_play_circle_filled_white_24dp.png new file mode 100644 index 000000000..30330cfad Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_play_circle_filled_white_24dp.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_pause_white_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_pause_white_24dp.png new file mode 100644 index 000000000..660ac6585 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_pause_white_24dp.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_play_circle_filled_white_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_play_circle_filled_white_24dp.png new file mode 100644 index 000000000..9dc082586 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_play_circle_filled_white_24dp.png differ diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index cf87951b6..fa767bdf4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -50,6 +50,8 @@ VIDEO & AUDIO INFO ETC + %1$s - NewPipe + Playing in background Video preview thumbnail