From 943027ffdd3436c05cdc27b0ff7cc0e7e0f475cf Mon Sep 17 00:00:00 2001 From: Adam Howard Date: Tue, 24 Nov 2015 00:40:36 +0000 Subject: [PATCH 01/12] implemented stage 1 ultra-basic background play of videos; see https://github.com/theScrabi/NewPipe/wiki/Background-Playback-Mini-Roadmap --- app/src/main/AndroidManifest.xml | 3 + .../org/schabi/newpipe/ActionBarHandler.java | 17 ++++- .../org/schabi/newpipe/BackgroundPlayer.java | 73 +++++++++++++++++++ 3 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 07029455e..b91e44fee 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -71,6 +71,9 @@ android:parentActivityName=".VideoItemDetailActivity" > + + diff --git a/app/src/main/java/org/schabi/newpipe/ActionBarHandler.java b/app/src/main/java/org/schabi/newpipe/ActionBarHandler.java index 4f28b606d..c14f93b56 100644 --- a/app/src/main/java/org/schabi/newpipe/ActionBarHandler.java +++ b/app/src/main/java/org/schabi/newpipe/ActionBarHandler.java @@ -287,13 +287,26 @@ public class ActionBarHandler { } public void playAudio() { - Intent intent = new Intent(); + boolean b = true;//todo: replace with preference + Intent intent; + if (b)//internal (background) music player: explicit intent + { + intent = new Intent(activity, BackgroundPlayer.class); + intent.setAction(Intent.ACTION_VIEW); + intent.setDataAndType(Uri.parse(audioStream.url), + MediaFormat.getMimeById(audioStream.format)); + intent.putExtra(Intent.EXTRA_TITLE, videoTitle); + intent.putExtra("title", videoTitle); + activity.startService(intent); + } + /*Intent intent = new Intent(); try { intent.setAction(Intent.ACTION_VIEW); intent.setDataAndType(Uri.parse(audioStream.url), MediaFormat.getMimeById(audioStream.format)); intent.putExtra(Intent.EXTRA_TITLE, videoTitle); intent.putExtra("title", videoTitle); + activity.startActivity(intent); // HERE !!! } catch (Exception e) { e.printStackTrace(); @@ -317,6 +330,6 @@ public class ActionBarHandler { builder.create().show(); Log.e(TAG, "Either no Streaming player for audio was installed, or something important crashed:"); e.printStackTrace(); - } + }*/ } } diff --git a/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java b/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java new file mode 100644 index 000000000..b47a59248 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java @@ -0,0 +1,73 @@ +package org.schabi.newpipe; + +import android.app.IntentService; +import android.app.Notification; +import android.app.PendingIntent; +import android.content.Intent; +import android.media.AudioManager; +import android.media.MediaPlayer; +import android.os.PowerManager; + +import java.io.IOException; + +/** + * Created by Adam Howard on 08/11/15. + * + * Copyright (c) Adam Howard 2015 + * + * BackgroundPlayer.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 . + */ +public class BackgroundPlayer extends IntentService /*implements MediaPlayer.OnPreparedListener*/ { + + private static final String TAG = BackgroundPlayer.class.toString(); + /** + * Creates an IntentService. Invoked by your subclass's constructor. + */ + public BackgroundPlayer() { + super(TAG); + } + + @Override + protected void onHandleIntent(Intent intent) { + String source = intent.getDataString(); + + MediaPlayer mediaPlayer = new MediaPlayer(); + //mediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);//cpu lock apparently + mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); + try { + mediaPlayer.setDataSource(source); + mediaPlayer.prepare(); // IntentService already puts us in a separate worker thread, + //so calling the blocking prepare() method should be ok + } catch (IOException ioe) { + ioe.printStackTrace(); + //can't really do anything useful without a file to play; exit early + return; + } + //mediaPlayer.setOnPreparedListener(this); + mediaPlayer.start(); +/* + PendingIntent pi = PendingIntent.getActivity(getApplicationContext(), 0, + new Intent(getApplicationContext(), MainActivity.class), + PendingIntent.FLAG_UPDATE_CURRENT); + Notification notification = new Notification(); + notification.tickerText = text; + notification.icon = R.drawable.play0; + notification.flags |= Notification.FLAG_ONGOING_EVENT; + notification.setLatestEventInfo(getApplicationContext(), "MusicPlayerSample", + "Playing: " + songName, pi); + startForeground(NOTIFICATION_ID, notification);*/ + } +} From 0f93a45b9d94c9834904955117ca8cb33466739e Mon Sep 17 00:00:00 2001 From: Adam Howard Date: Wed, 25 Nov 2015 15:19:50 +0000 Subject: [PATCH 02/12] reimplemented BackgroundPlayer extending Service, not IntentService. See http://stackoverflow.com/questions/17237746 and http://stackoverflow.com/questions/8690198 --- app/src/main/AndroidManifest.xml | 1 + .../org/schabi/newpipe/ActionBarHandler.java | 65 ++++---- .../org/schabi/newpipe/BackgroundPlayer.java | 147 +++++++++++++++--- .../services/youtube/YoutubeExtractor.java | 4 +- 4 files changed, 165 insertions(+), 52 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b91e44fee..3a7547137 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -3,6 +3,7 @@ package="org.schabi.newpipe" > + . */ -public class BackgroundPlayer extends IntentService /*implements MediaPlayer.OnPreparedListener*/ { + +/**Plays the audio stream of videos in the background. */ +public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPreparedListener*/ { private static final String TAG = BackgroundPlayer.class.toString(); - /** - * Creates an IntentService. Invoked by your subclass's constructor. - */ + private Looper mServiceLooper; + private ServiceHandler mServiceHandler; + public BackgroundPlayer() { - super(TAG); + super(); } @Override + public void onCreate() { + // Start up the thread running the service. Note that we create a + // separate thread because the service normally runs in the process's + // main thread, which we don't want to block. We also make it + // background priority so CPU-intensive work will not disrupt our UI. + super.onCreate(); + HandlerThread thread = new HandlerThread(TAG, Process.THREAD_PRIORITY_BACKGROUND); + thread.start(); + + // Get the HandlerThread's Looper and use it for our Handler + mServiceLooper = thread.getLooper(); + mServiceHandler = new ServiceHandler(mServiceLooper); + } + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + Toast.makeText(this, "Playing in background", Toast.LENGTH_SHORT).show();//todo:translation string + + // For each start request, send a message to start a job and deliver the + // start ID so we know which request we're stopping when we finish the job + Message msg = mServiceHandler.obtainMessage(); + msg.arg1 = startId; + msg.obj = intent; + mServiceHandler.sendMessage(msg); + + // If we get killed, after returning from here, don't restart + return START_NOT_STICKY; + } + + @Override + public IBinder onBind(Intent intent) { + // We don't provide binding yet, so return null + return null; + } + + @Override + public void onDestroy() { + //Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show(); + mServiceLooper.quit(); + } + protected void onHandleIntent(Intent intent) { String source = intent.getDataString(); + if (intent.getAction().equals(ACTION_PLAY)) { + mMediaPlayer.setOnPreparedListener(this); + mMediaPlayer.prepareAsync(); // prepare async to not block main thread + } + + MediaPlayer mediaPlayer = new MediaPlayer(); - //mediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);//cpu lock apparently + mediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);//cpu lock mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); try { mediaPlayer.setDataSource(source); - mediaPlayer.prepare(); // IntentService already puts us in a separate worker thread, + mediaPlayer.prepare(); //IntentService already puts us in a separate worker thread, //so calling the blocking prepare() method should be ok } catch (IOException ioe) { ioe.printStackTrace(); //can't really do anything useful without a file to play; exit early return; } + + WifiManager wifiMgr = ((WifiManager)getSystemService(Context.WIFI_SERVICE)); + WifiManager.WifiLock wifiLock = wifiMgr.createWifiLock(WifiManager.WIFI_MODE_FULL, TAG); + + mediaPlayer.setOnCompletionListener(new EndListener(wifiLock));//listen for end of video +/* + //get audio focus + AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); + int result = audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, + AudioManager.AUDIOFOCUS_GAIN); + + if (result != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { + // could not get audio focus. + } +*/ + wifiLock.acquire(); //mediaPlayer.setOnPreparedListener(this); mediaPlayer.start(); + + String videoTitle = intent.getStringExtra("title"); + + Notification noti = new NotificationCompat.Builder(this) + .setPriority(Notification.PRIORITY_LOW) + .setCategory(Notification.CATEGORY_TRANSPORT) + .setContentTitle(videoTitle) + .setContentText("NewPipe is playing in the background")//todo: add translatable string + .setOngoing(true) + .setSmallIcon(R.mipmap.ic_launcher) + .build(); + + startForeground(TAG.hashCode(), noti); + } /* - PendingIntent pi = PendingIntent.getActivity(getApplicationContext(), 0, - new Intent(getApplicationContext(), MainActivity.class), - PendingIntent.FLAG_UPDATE_CURRENT); - Notification notification = new Notification(); - notification.tickerText = text; - notification.icon = R.drawable.play0; - notification.flags |= Notification.FLAG_ONGOING_EVENT; - notification.setLatestEventInfo(getApplicationContext(), "MusicPlayerSample", - "Playing: " + songName, pi); - startForeground(NOTIFICATION_ID, notification);*/ + private class ListenerThread extends Thread implements AudioManager.OnAudioFocusChangeListener { + + } + + @Override + public void onAudioFocusChange(int focusChange) { + + }*/ + + private class EndListener implements MediaPlayer.OnCompletionListener { + private WifiManager.WifiLock wl; + public EndListener(WifiManager.WifiLock wifiLock) { + this.wl = wifiLock; + } + + @Override + public void onCompletion(MediaPlayer mp) { + wl.release(); + } + } + + // Handler that receives messages from the thread + private final class ServiceHandler extends Handler { + public ServiceHandler(Looper looper) { + super(looper); + } + @Override + public void handleMessage(Message msg) { + onHandleIntent((Intent)msg.obj); + // Stop the service using the startId, so that we don't stop + // the service in the middle of handling another job + stopSelfResult(msg.arg1); + } } } diff --git a/app/src/main/java/org/schabi/newpipe/services/youtube/YoutubeExtractor.java b/app/src/main/java/org/schabi/newpipe/services/youtube/YoutubeExtractor.java index cb996d2ef..cca460902 100644 --- a/app/src/main/java/org/schabi/newpipe/services/youtube/YoutubeExtractor.java +++ b/app/src/main/java/org/schabi/newpipe/services/youtube/YoutubeExtractor.java @@ -509,8 +509,8 @@ public class YoutubeExtractor extends Extractor { //this page causes the NullPointerException, after finding it by searching for "tjvg": //https://www.youtube.com/watch?v=Uqg0aEhLFAg String views = li.select("span.view-count").first().text(); - Log.i(TAG, "title:"+info.title); - Log.i(TAG, "view count:"+views); + //Log.i(TAG, "title:"+info.title); + //Log.i(TAG, "view count:"+views); try { info.view_count = Long.parseLong(li.select("span.view-count") .first().text().replaceAll("[^\\d]", "")); From 6b2c3217ab9db6821dce21cd9e6f029bdffe7063 Mon Sep 17 00:00:00 2001 From: Adam Howard Date: Wed, 25 Nov 2015 17:18:01 +0000 Subject: [PATCH 03/12] Implemented a playback notification with a progress bar. No playback controls yet. --- app/src/main/AndroidManifest.xml | 5 +- .../org/schabi/newpipe/BackgroundPlayer.java | 184 ++++++++++-------- 2 files changed, 106 insertions(+), 83 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3a7547137..23bce5eab 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -72,7 +72,10 @@ android:parentActivityName=".VideoItemDetailActivity" > - + Date: Wed, 25 Nov 2015 17:36:01 +0000 Subject: [PATCH 04/12] cleaned up BackgroundPlayer code a little --- .../org/schabi/newpipe/BackgroundPlayer.java | 27 +++---------------- 1 file changed, 3 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java b/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java index 9f3c1b024..f65cee56b 100644 --- a/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java @@ -1,6 +1,5 @@ package org.schabi.newpipe; -import android.app.IntentService; import android.app.Notification; import android.app.NotificationManager; import android.app.Service; @@ -9,17 +8,11 @@ import android.content.Intent; import android.media.AudioManager; import android.media.MediaPlayer; import android.net.wifi.WifiManager; -import android.os.Handler; -import android.os.HandlerThread; import android.os.IBinder; -import android.os.Looper; -import android.os.Message; import android.os.PowerManager; import android.support.v7.app.NotificationCompat; import android.util.Log; import android.widget.Toast; -import android.os.Process; -import android.widget.VideoView; import java.io.IOException; @@ -53,23 +46,11 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare public BackgroundPlayer() { super(); - - VideoView v; } @Override public void onCreate() { - // Start up the thread running the service. Note that we create a - // separate thread because the service normally runs in the process's - // main thread, which we don't want to block. We also make it - // background priority so CPU-intensive work will not disrupt our UI. super.onCreate(); - //HandlerThread thread = new HandlerThread(TAG, Process.THREAD_PRIORITY_BACKGROUND); - //thread.start(); - - // Get the HandlerThread's Looper and use it for our Handler - //mServiceLooper = thread.getLooper(); - //mServiceHandler = new ServiceHandler(mServiceLooper); } @Override public int onStartCommand(Intent intent, int flags, int startId) { @@ -94,13 +75,9 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare @Override public void onDestroy() { //Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show(); - //mServiceLooper.quit(); - //if (mMediaPlayer != null) mMediaPlayer.release(); - //todo: call MediaPlayer.release() as soon as video is complete } private class PlayerThread extends Thread { - private MediaPlayer mediaPlayer; private String source; private String title; @@ -120,6 +97,7 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare mediaPlayer.prepare(); //We are already in a separate worker thread, //so calling the blocking prepare() method should be ok + //alternatively: //mediaPlayer.setOnPreparedListener(this); //mediaPlayer.prepareAsync(); //prepare async to not block main thread } catch (IOException ioe) { @@ -175,7 +153,7 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare noteMgr.notify(noteID, noteBuilder.build()); } noteBuilder.setProgress(0, 0, false);//remove bar - //noteMgr.notify(0, noteBuilder.build()); + noteMgr.cancel(noteID); } } /* @@ -198,6 +176,7 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare wl.release();//release wifilock stopForeground(true);//remove ongoing notification stopSelf(); + mp.release(); //todo:release cpu lock } } From aebfeb98aaf391f1409b5d98d31801a2830406c1 Mon Sep 17 00:00:00 2001 From: Adam Howard Date: Sun, 29 Nov 2015 17:05:44 +0000 Subject: [PATCH 05/12] sync so I can clone this branch on another machine --- .../org/schabi/newpipe/BackgroundPlayer.java | 18 +++++++++++++++++- .../newpipe/services/StreamingService.java | 2 +- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java b/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java index f65cee56b..cd7346913 100644 --- a/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java @@ -2,6 +2,7 @@ package org.schabi.newpipe; import android.app.Notification; import android.app.NotificationManager; +import android.app.PendingIntent; import android.app.Service; import android.content.Context; import android.content.Intent; @@ -50,6 +51,8 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare @Override public void onCreate() { + PendingIntent pi = PendingIntent.getActivity(this, 0, + new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0); super.onCreate(); } @Override @@ -124,7 +127,20 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare }*/ wifiLock.acquire(); mediaPlayer.start(); - +/* + 1. For each button in the notification, create an Intent pointing to the handling class + 2. From this, create a corresponding PendingIntent. + 3. Then, for each button, call NotificationBuilder.addAction(). + the exact method signature will depend on whether you just specify the icon,label etc (deprecated), + or if you also have to create a Notification.Action (and Notification.Action.Builder). + in any case, in the class referred to in the explicit intent, + 4. Write the method body of whatever callback android says to use for a service. + Probably onStartCommand. But isn't that only called when startService() is? and + we need to call this whenever a notification button is pressed! we don't want to restart + the service every time the button is pressed! Oh I don't know yet.... + see: http://www.vogella.com/tutorials/AndroidNotifications/article.html + and maybe also: http://stackoverflow.com/questions/10613524 +*/ //mediaPlayer.getCurrentPosition() int vidLength = mediaPlayer.getDuration(); //todo: make it so that tapping the notification brings you back to the Video's DetailActivity diff --git a/app/src/main/java/org/schabi/newpipe/services/StreamingService.java b/app/src/main/java/org/schabi/newpipe/services/StreamingService.java index 4321340c6..fbcd31f10 100644 --- a/app/src/main/java/org/schabi/newpipe/services/StreamingService.java +++ b/app/src/main/java/org/schabi/newpipe/services/StreamingService.java @@ -30,6 +30,6 @@ public interface StreamingService { /**When a VIEW_ACTION is caught this function will test if the url delivered within the calling Intent was meant to be watched with this Service. - Return false if this service shall not allow to be callean through ACTIONs.*/ + Return false if this service shall not allow to be called through ACTIONs.*/ boolean acceptUrl(String videoUrl); } From cd2d88781a12e20f2b068edb5653e6b578b65950 Mon Sep 17 00:00:00 2001 From: Adam Howard Date: Thu, 17 Dec 2015 17:49:12 +0000 Subject: [PATCH 06/12] implemented play/pause and cancel controls --- .../org/schabi/newpipe/BackgroundPlayer.java | 206 +++++++++++++----- 1 file changed, 157 insertions(+), 49 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java b/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java index cd7346913..2455a2a86 100644 --- a/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java @@ -4,8 +4,10 @@ import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; +import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.media.AudioManager; import android.media.MediaPlayer; import android.net.wifi.WifiManager; @@ -19,7 +21,6 @@ import java.io.IOException; /** * Created by Adam Howard on 08/11/15. - * * Copyright (c) Adam Howard 2015 * * BackgroundPlayer.java is part of NewPipe. @@ -38,10 +39,12 @@ import java.io.IOException; * along with NewPipe. If not, see . */ -/**Plays the audio stream of videos in the background. */ +/**Plays the audio stream of videos in the background.*/ 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 Looper mServiceLooper; //private ServiceHandler mServiceHandler; @@ -51,8 +54,8 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare @Override public void onCreate() { - PendingIntent pi = PendingIntent.getActivity(this, 0, - new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0); + /*PendingIntent pi = PendingIntent.getActivity(this, 0, + new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);*/ super.onCreate(); } @Override @@ -60,8 +63,10 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare Toast.makeText(this, "Playing in background", Toast.LENGTH_SHORT).show();//todo:translation string String source = intent.getDataString(); + //Log.i(TAG, "backgroundPLayer source:"+source); String videoTitle = intent.getStringExtra("title"); + //do nearly everything in a separate thread PlayerThread player = new PlayerThread(source, videoTitle, this); player.start(); @@ -81,10 +86,15 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare } private class PlayerThread extends Thread { - private MediaPlayer mediaPlayer; + MediaPlayer mediaPlayer; private String source; private String title; + private int noteID = TAG.hashCode(); private BackgroundPlayer owner; + private NotificationManager noteMgr; + private NotificationCompat.Builder noteBuilder; + private WifiManager.WifiLock wifiLock; + public PlayerThread(String src, String title, BackgroundPlayer owner) { this.source = src; this.title = title; @@ -112,7 +122,7 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare } WifiManager wifiMgr = ((WifiManager)getSystemService(Context.WIFI_SERVICE)); - WifiManager.WifiLock wifiLock = wifiMgr.createWifiLock(WifiManager.WIFI_MODE_FULL, TAG); + wifiLock = wifiMgr.createWifiLock(WifiManager.WIFI_MODE_FULL, TAG); mediaPlayer.setOnCompletionListener(new EndListener(wifiLock));//listen for end of video @@ -127,49 +137,164 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare }*/ wifiLock.acquire(); mediaPlayer.start(); -/* - 1. For each button in the notification, create an Intent pointing to the handling class - 2. From this, create a corresponding PendingIntent. - 3. Then, for each button, call NotificationBuilder.addAction(). - the exact method signature will depend on whether you just specify the icon,label etc (deprecated), - or if you also have to create a Notification.Action (and Notification.Action.Builder). - in any case, in the class referred to in the explicit intent, - 4. Write the method body of whatever callback android says to use for a service. - Probably onStartCommand. But isn't that only called when startService() is? and - we need to call this whenever a notification button is pressed! we don't want to restart - the service every time the button is pressed! Oh I don't know yet.... - see: http://www.vogella.com/tutorials/AndroidNotifications/article.html - and maybe also: http://stackoverflow.com/questions/10613524 -*/ + //mediaPlayer.getCurrentPosition() int vidLength = mediaPlayer.getDuration(); - //todo: make it so that tapping the notification brings you back to the Video's DetailActivity - NotificationCompat.Builder noteBuilder = new NotificationCompat.Builder(owner); + + //Intent genericIntent = new Intent(owner, owner.getClass()); + + //PendingIntent playPI = PendingIntent.getService(owner, noteID, genericIntent, 0); + PendingIntent playPI = PendingIntent.getBroadcast(owner, noteID, new Intent(ACTION_PLAYPAUSE), PendingIntent.FLAG_UPDATE_CURRENT); + + NotificationCompat.Action.Builder buttonBuilder = + new NotificationCompat.Action.Builder(R.drawable.ic_play_arrow_black, + "Play", playPI);//todo:translatable string + NotificationCompat.Action playButton = buttonBuilder.build(); + + PendingIntent stopPI = PendingIntent.getBroadcast(owner, noteID, + new Intent(ACTION_STOP), PendingIntent.FLAG_UPDATE_CURRENT); + + IntentFilter filter = new IntentFilter(); + filter.setPriority(Integer.MAX_VALUE); + filter.addAction(ACTION_PLAYPAUSE); + filter.addAction(ACTION_STOP); + registerReceiver(broadcastReceiver, filter); + + //playPauseButton + //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 + //.setAutoCancel(!mediaPlayer.isPlaying()) .setOngoing(true) - .setProgress(vidLength, 0, false) - .setSmallIcon(R.mipmap.ic_launcher); + .setDeleteIntent(stopPI) + //.setProgress(vidLength, 0, false) //doesn't fit with Notification.MediaStyle + .setSmallIcon(R.mipmap.ic_launcher) + .setTicker(title + " - NewPipe") + .addAction(playButton); +/* .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) + .setLargeIcon(cover)*/ + + noteBuilder.setStyle(new NotificationCompat.MediaStyle() + //.setMediaSession(mMediaSession.getSessionToken()) + .setShowActionsInCompactView(new int[] {0}) + .setShowCancelButton(true) + .setCancelButtonIntent(stopPI) + ); - int noteID = TAG.hashCode(); startForeground(noteID, noteBuilder.build()); - NotificationManager noteMgr = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); - //update every 3s or 4 times in the video, whichever is shorter - int sleepTime = Math.min(3000, (int)((double)vidLength/4)); + + //currently decommissioned progressbar looping update code - works, but doesn't fit inside + //Notification.MediaStyle Notification layout. + noteMgr = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); + /* + //update every 2s or 4 times in the video, whichever is shorter + int sleepTime = Math.min(2000, (int)((double)vidLength/4)); while(mediaPlayer.isPlaying()) { + noteBuilder.setProgress(vidLength, mediaPlayer.getCurrentPosition(), false); + noteMgr.notify(noteID, noteBuilder.build()); try { Thread.sleep(sleepTime); } catch (InterruptedException e) { Log.d(TAG, "sleep failure"); } - noteBuilder.setProgress(vidLength, mediaPlayer.getCurrentPosition(), false); - noteMgr.notify(noteID, noteBuilder.build()); + }*/ + + } +/* MediaMetadataCompat metaData = mMediaSession.getController().getMetadata(); + String title = metaData.getString(MediaMetadataCompat.METADATA_KEY_TITLE); + String artist = metaData.getString(MediaMetadataCompat.METADATA_KEY_ALBUM_ARTIST); + String album = metaData.getString(MediaMetadataCompat.METADATA_KEY_ALBUM); + Bitmap cover = metaData.getBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART); + if (cover == null) + cover = BitmapFactory.decodeResource(VLCApplication.getAppContext().getResources(), R.drawable.icon); + + Notification notification; +//set up switch-back-to functionality + PendingIntent pendingIntent; + if (canSwitchToVideo()) { + // Resume VideoPlayerActivity from ACTION_REMOTE_SWITCH_VIDEO intent + final Intent notificationIntent = new Intent(ACTION_REMOTE_SWITCH_VIDEO); + pendingIntent = PendingIntent.getBroadcast(this, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT); + } else { + // Resume AudioPlayerActivity + + final Intent notificationIntent = getPackageManager().getLaunchIntentForPackage(getPackageName()); + notificationIntent.setAction(AudioPlayerContainerActivity.ACTION_SHOW_PLAYER); + notificationIntent.addCategory(Intent.CATEGORY_LAUNCHER); + pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT); + } + builder.setContentIntent(pendingIntent); + + //set up and add media control buttons + PendingIntent piBackward = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_REMOTE_BACKWARD), PendingIntent.FLAG_UPDATE_CURRENT); + PendingIntent piPlay = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_REMOTE_PLAYPAUSE), PendingIntent.FLAG_UPDATE_CURRENT); + PendingIntent piForward = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_REMOTE_FORWARD), PendingIntent.FLAG_UPDATE_CURRENT); + + builder.addAction(R.drawable.ic_previous_w, getString(R.string.previous), piBackward); + if (mMediaPlayer.isPlaying()) + builder.addAction(R.drawable.ic_pause_w, getString(R.string.pause), piPlay); + else + builder.addAction(R.drawable.ic_play_w, getString(R.string.play), piPlay); + builder.addAction(R.drawable.ic_next_w, getString(R.string.next), piForward); + + //post-start service + if (!AndroidUtil.isLolliPopOrLater() || mMediaPlayer.isPlaying()) + startForeground(3, notification); + else { + stopForeground(false); + NotificationManagerCompat.from(this).notify(3, notification); + } + }*/ + + private final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + Log.i(TAG, "received broadcast action:"+action); + if(action.equals(ACTION_PLAYPAUSE)) { + if(mediaPlayer.isPlaying()) { + mediaPlayer.pause(); + } + else { + mediaPlayer.start(); + } + } + else if(action.equals(ACTION_STOP)) { + mediaPlayer.stop(); + afterPlayCleanup(); + } + } + }; + + private void afterPlayCleanup() { + //noteBuilder.setProgress(0, 0, false);//remove progress bar + noteMgr.cancel(noteID);//remove notification + unregisterReceiver(broadcastReceiver); + mediaPlayer.release();//release system resources + + + wifiLock.release();//release wifilock + stopForeground(true);//remove foreground status of service; make us killable + + stopSelf(); + //todo:release cpu lock + } + + private class EndListener implements MediaPlayer.OnCompletionListener { + private WifiManager.WifiLock wl; + public EndListener(WifiManager.WifiLock wifiLock) { + this.wl = wifiLock; + } + + @Override + public void onCompletion(MediaPlayer mp) { + afterPlayCleanup(); } - noteBuilder.setProgress(0, 0, false);//remove bar - noteMgr.cancel(noteID); } } /* @@ -179,21 +304,4 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare } }*/ - - - private class EndListener implements MediaPlayer.OnCompletionListener { - private WifiManager.WifiLock wl; - public EndListener(WifiManager.WifiLock wifiLock) { - this.wl = wifiLock; - } - - @Override - public void onCompletion(MediaPlayer mp) { - wl.release();//release wifilock - stopForeground(true);//remove ongoing notification - stopSelf(); - mp.release(); - //todo:release cpu lock - } - } } From 3e94d18fe18b4b1803df6779c24cf9ae54f51ede Mon Sep 17 00:00:00 2001 From: Adam Howard Date: Thu, 17 Dec 2015 18:01:24 +0000 Subject: [PATCH 07/12] removed accidental 'git merge' command from manifest --- app/src/main/AndroidManifest.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 5f8db3ab3..05eda83c5 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,7 +2,6 @@ - git merge From 6a741de7d1efb1b8b18d41a76ea65253df11a1f9 Mon Sep 17 00:00:00 2001 From: Adam Howard Date: Thu, 17 Dec 2015 18:04:18 +0000 Subject: [PATCH 08/12] removed commented-out example code --- .../org/schabi/newpipe/BackgroundPlayer.java | 45 ------------------- 1 file changed, 45 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java b/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java index 2455a2a86..03e1eb40b 100644 --- a/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java @@ -205,51 +205,6 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare }*/ } -/* MediaMetadataCompat metaData = mMediaSession.getController().getMetadata(); - String title = metaData.getString(MediaMetadataCompat.METADATA_KEY_TITLE); - String artist = metaData.getString(MediaMetadataCompat.METADATA_KEY_ALBUM_ARTIST); - String album = metaData.getString(MediaMetadataCompat.METADATA_KEY_ALBUM); - Bitmap cover = metaData.getBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART); - if (cover == null) - cover = BitmapFactory.decodeResource(VLCApplication.getAppContext().getResources(), R.drawable.icon); - - Notification notification; -//set up switch-back-to functionality - PendingIntent pendingIntent; - if (canSwitchToVideo()) { - // Resume VideoPlayerActivity from ACTION_REMOTE_SWITCH_VIDEO intent - final Intent notificationIntent = new Intent(ACTION_REMOTE_SWITCH_VIDEO); - pendingIntent = PendingIntent.getBroadcast(this, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT); - } else { - // Resume AudioPlayerActivity - - final Intent notificationIntent = getPackageManager().getLaunchIntentForPackage(getPackageName()); - notificationIntent.setAction(AudioPlayerContainerActivity.ACTION_SHOW_PLAYER); - notificationIntent.addCategory(Intent.CATEGORY_LAUNCHER); - pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT); - } - builder.setContentIntent(pendingIntent); - - //set up and add media control buttons - PendingIntent piBackward = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_REMOTE_BACKWARD), PendingIntent.FLAG_UPDATE_CURRENT); - PendingIntent piPlay = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_REMOTE_PLAYPAUSE), PendingIntent.FLAG_UPDATE_CURRENT); - PendingIntent piForward = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_REMOTE_FORWARD), PendingIntent.FLAG_UPDATE_CURRENT); - - builder.addAction(R.drawable.ic_previous_w, getString(R.string.previous), piBackward); - if (mMediaPlayer.isPlaying()) - builder.addAction(R.drawable.ic_pause_w, getString(R.string.pause), piPlay); - else - builder.addAction(R.drawable.ic_play_w, getString(R.string.play), piPlay); - builder.addAction(R.drawable.ic_next_w, getString(R.string.next), piForward); - - //post-start service - if (!AndroidUtil.isLolliPopOrLater() || mMediaPlayer.isPlaying()) - startForeground(3, notification); - else { - stopForeground(false); - NotificationManagerCompat.from(this).notify(3, notification); - } - }*/ private final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { @Override From f2e761c07cd89eaa472be31f4c4c94b68974d63e Mon Sep 17 00:00:00 2001 From: Adam Howard Date: Thu, 17 Dec 2015 18:27:35 +0000 Subject: [PATCH 09/12] added reacquisition of CPU lock after resuming --- app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java b/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java index 03e1eb40b..7c73d4402 100644 --- a/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java @@ -216,11 +216,13 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare mediaPlayer.pause(); } else { + //reacquire CPU lock after releasing it on pause + mediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK); mediaPlayer.start(); } } else if(action.equals(ACTION_STOP)) { - mediaPlayer.stop(); + mediaPlayer.stop();//this auto-releases CPU lock afterPlayCleanup(); } } @@ -237,7 +239,6 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare stopForeground(true);//remove foreground status of service; make us killable stopSelf(); - //todo:release cpu lock } private class EndListener implements MediaPlayer.OnCompletionListener { From 25c5f95ad961d810f2ae5fd9eae50e3f0bd6d20f Mon Sep 17 00:00:00 2001 From: Adam Howard Date: Sun, 20 Dec 2015 00:08:12 +0000 Subject: [PATCH 10/12] added white play button icon for notification controls; pause button soon to follow. Some checks for audioStreams being null added, along with minor semnatic restructuring of parseDashManifest() --- .../org/schabi/newpipe/ActionBarHandler.java | 5 +++ .../org/schabi/newpipe/BackgroundPlayer.java | 32 +++++++----------- .../youtube/YoutubeVideoExtractor.java | 28 +++++++++------ .../ic_play_arrow_white_48dp.png | Bin 0 -> 283 bytes .../ic_play_arrow_white_48dp.png | Bin 0 -> 220 bytes .../ic_play_arrow_white_48dp.png | Bin 0 -> 343 bytes .../ic_play_arrow_white_48dp.png | Bin 0 -> 461 bytes .../ic_play_arrow_white_48dp.png | Bin 0 -> 605 bytes 8 files changed, 34 insertions(+), 31 deletions(-) create mode 100644 app/src/main/res/drawable-hdpi/ic_play_arrow_white_48dp.png create mode 100644 app/src/main/res/drawable-mdpi/ic_play_arrow_white_48dp.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_play_arrow_white_48dp.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_play_arrow_white_48dp.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_play_arrow_white_48dp.png diff --git a/app/src/main/java/org/schabi/newpipe/ActionBarHandler.java b/app/src/main/java/org/schabi/newpipe/ActionBarHandler.java index 7372f7db8..28fbbac37 100644 --- a/app/src/main/java/org/schabi/newpipe/ActionBarHandler.java +++ b/app/src/main/java/org/schabi/newpipe/ActionBarHandler.java @@ -120,6 +120,9 @@ class ActionBarHandler { } } } + else { + Log.e(TAG, "FAILED to set audioStream value!"); + } } private void selectFormatItem(int i) { @@ -301,6 +304,8 @@ class ActionBarHandler { 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); diff --git a/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java b/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java index 7c73d4402..443f7f846 100644 --- a/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java @@ -45,8 +45,6 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare 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 Looper mServiceLooper; - //private ServiceHandler mServiceHandler; public BackgroundPlayer() { super(); @@ -138,29 +136,23 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare wifiLock.acquire(); mediaPlayer.start(); - //mediaPlayer.getCurrentPosition() - int vidLength = mediaPlayer.getDuration(); - - //Intent genericIntent = new Intent(owner, owner.getClass()); - - //PendingIntent playPI = PendingIntent.getService(owner, noteID, genericIntent, 0); - PendingIntent playPI = PendingIntent.getBroadcast(owner, noteID, new Intent(ACTION_PLAYPAUSE), PendingIntent.FLAG_UPDATE_CURRENT); - - NotificationCompat.Action.Builder buttonBuilder = - new NotificationCompat.Action.Builder(R.drawable.ic_play_arrow_black, - "Play", playPI);//todo:translatable string - NotificationCompat.Action playButton = buttonBuilder.build(); - - PendingIntent stopPI = PendingIntent.getBroadcast(owner, noteID, - new Intent(ACTION_STOP), PendingIntent.FLAG_UPDATE_CURRENT); - IntentFilter filter = new IntentFilter(); filter.setPriority(Integer.MAX_VALUE); filter.addAction(ACTION_PLAYPAUSE); filter.addAction(ACTION_STOP); registerReceiver(broadcastReceiver, filter); - //playPauseButton + 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(); + + 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); @@ -232,7 +224,7 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare //noteBuilder.setProgress(0, 0, false);//remove progress bar noteMgr.cancel(noteID);//remove notification unregisterReceiver(broadcastReceiver); - mediaPlayer.release();//release system resources + mediaPlayer.release();//release mediaPlayer's system resources wifiLock.release();//release wifilock diff --git a/app/src/main/java/org/schabi/newpipe/services/youtube/YoutubeVideoExtractor.java b/app/src/main/java/org/schabi/newpipe/services/youtube/YoutubeVideoExtractor.java index 3112d7f0c..82eba52e9 100644 --- a/app/src/main/java/org/schabi/newpipe/services/youtube/YoutubeVideoExtractor.java +++ b/app/src/main/java/org/schabi/newpipe/services/youtube/YoutubeVideoExtractor.java @@ -371,6 +371,16 @@ public class YoutubeVideoExtractor extends VideoExtractor { //todo: replace this with a call to getVideoId, if possible videoInfo.id = matchGroup1("v=([0-9a-zA-Z_-]{11})", pageUrl); + if(videoInfo.audioStreams == null + || videoInfo.audioStreams.length == 0) { + Log.e(TAG, "uninitialised audio streams!"); + } + + if(videoInfo.videoStreams == null + || videoInfo.videoStreams.length == 0) { + Log.e(TAG, "uninitialised video streams!"); + } + videoInfo.age_limit = 0; //average rating @@ -445,13 +455,14 @@ public class YoutubeVideoExtractor extends VideoExtractor { try { XmlPullParser parser = Xml.newPullParser(); parser.setInput(new StringReader(dashDoc)); - int eventType = parser.getEventType(); String tagName = ""; String currentMimeType = ""; int currentBandwidth = -1; int currentSamplingRate = -1; boolean currentTagIsBaseUrl = false; - while(eventType != XmlPullParser.END_DOCUMENT) { + for(int eventType = parser.getEventType(); + eventType != XmlPullParser.END_DOCUMENT; + eventType = parser.next() ) { switch(eventType) { case XmlPullParser.START_TAG: tagName = parser.getName(); @@ -465,8 +476,8 @@ public class YoutubeVideoExtractor extends VideoExtractor { } else if(tagName.equals("BaseURL")) { currentTagIsBaseUrl = true; } - break; + case XmlPullParser.TEXT: if(currentTagIsBaseUrl && (currentMimeType.contains("audio"))) { @@ -479,16 +490,14 @@ public class YoutubeVideoExtractor extends VideoExtractor { audioStreams.add(new VideoInfo.AudioStream(parser.getText(), format, currentBandwidth, currentSamplingRate)); } + //missing break here? case XmlPullParser.END_TAG: if(tagName.equals("AdaptationSet")) { currentMimeType = ""; } else if(tagName.equals("BaseURL")) { currentTagIsBaseUrl = false; - } - break; - default: + }//no break needed here } - eventType = parser.next(); } } catch(Exception e) { e.printStackTrace(); @@ -583,10 +592,7 @@ public class YoutubeVideoExtractor extends VideoExtractor { e.printStackTrace(); } Context.exit(); - if(result != null) - return result.toString(); - else - return ""; + return (result == null ? "" : result.toString()); } private String cleanUrl(String complexUrl) { diff --git a/app/src/main/res/drawable-hdpi/ic_play_arrow_white_48dp.png b/app/src/main/res/drawable-hdpi/ic_play_arrow_white_48dp.png new file mode 100644 index 0000000000000000000000000000000000000000..547ef30aacdebbd5bc27a3831971aa49be8813f7 GIT binary patch literal 283 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY0wn)GsXhaw9(lSrhEy=Vy|FR(PyjfM61bK%=q7O8Xj0w7EPdhfr5^#S_IEwe==vgFzHZ{arrqiL9p^2}oCQR8HlO`a zfBt>_q&-EaGMH-9&z)oSy0%IOibq!5=i7xQ8?znl*Ho#q?l1C zmLwh%pdb>pKr}hv!ldkF|5nzo_`k zc}eR_hl%VF4-<)DT=alRfHl0KMErSu6_?hE1x;YW&OCE+==ML_XMw(D@O1TaS?83{ F1OO`naDo5; literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/ic_play_arrow_white_48dp.png b/app/src/main/res/drawable-mdpi/ic_play_arrow_white_48dp.png new file mode 100644 index 0000000000000000000000000000000000000000..a3c80e73daa9dc4b85cddf9421b7127a4e18ac5d GIT binary patch literal 220 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA0wn)(8}b0D#hxyXAr*{ouNm?la*%QRSeCek zK}3Xig#+sj2GIvh!e1Mh%dY8tm)JkC<%w#{kNWLqKY43+mi=hInq~SfM{=M2eECLk zbvI##h#NZ@*2LVfaQK$+p6S94LraHmPZSsgTe~DWM4fm)lPg literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_play_arrow_white_48dp.png b/app/src/main/res/drawable-xhdpi/ic_play_arrow_white_48dp.png new file mode 100644 index 0000000000000000000000000000000000000000..be5c062b5feeba5eff766b2fdae6dccb60cb4b0e GIT binary patch literal 343 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD0wg^q?%&M7z$oYG;uuoF`1aODUuH)UwnS^i z62=e)(*V{`2k`*b5=Y_d%(4?EPx_&_WMu+pnDW{BolE^Uxj)}+yLIc`8R zg{90Lt0f&`?lL^eViO2AZ`iSm@yJ!6R31a2DNst&xD8@?udTeN#I8%r_sg2!eom$?*X_%R&Z!t~|1-cBYK4gm#+1_nk5gW={^?qALV VOCpPJ@c;vi!PC{xWt~$(69D@(h;je` literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/ic_play_arrow_white_48dp.png b/app/src/main/res/drawable-xxhdpi/ic_play_arrow_white_48dp.png new file mode 100644 index 0000000000000000000000000000000000000000..2745c3ab9297e89453fc82f5d3fd2aba163e3b37 GIT binary patch literal 461 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q1xWh(YZ)^zFi!DwaSW+oe0%4hCv%{L+r=G) znT%lzOe0!DGsL4>%MyiO9^|{TyY%sUrH;mw9Rd=LHutq1ECuvCCvX3G-WUyRuAF)L z=AXNp|MkzPod4UBc}q#z?Q^CJ9zU;^|7`KRf$#jkxaVvagf8UG|7;`P@a_D=d(Xr! zoVVQ9VZWfqenB501XPBM2&zX@Ao_^^g!h}1-e=@r3LF1d_$-XXz6+p4;3$0!>08tq4uJx_E zBNzhMWhb2Wg^F?Q^1c@%%<zopr02sN!rT_o{ literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/ic_play_arrow_white_48dp.png b/app/src/main/res/drawable-xxxhdpi/ic_play_arrow_white_48dp.png new file mode 100644 index 0000000000000000000000000000000000000000..8dbc4ea7c14058ce91746c5bc1767f49389f769e GIT binary patch literal 605 zcmeAS@N?(olHy`uVBq!ia0vp^2SAvE1xWt5x}=AJfl0;F#WAFU@y$U)Mg|5B<^@kT z{Lei)^PoHjPze$^5Wf9#jCFYqPauO^;0%`)d|3glS}&TkG%~6$G}Z*4jB7NM?mjo; z@4x6n=7&E%tDL@j_0`*b)%Q#rvh2%m*fyl?|GxG5T?P$?bKf_zGpHUYyY)MdQH0_7 z?>ov3EDvf5=PxJW*4R(HvUkbSv^anH4(o|{!&@Kx<#v_GX3Vp#0 zKxcFSoguTF;gJQa0E$%Z943Yj@$a^n+c)WbnZALicH+XjvSrWtH@@nt{-kl}utoo3 zMwNq{3cP*{i3Lm^&B6{6a~Sr_dhs-d!Lfje1IU-0!|>< Date: Sun, 20 Dec 2015 00:31:31 +0000 Subject: [PATCH 11/12] added preference to switch between external and internal audio players --- .../java/org/schabi/newpipe/ActionBarHandler.java | 10 ++++++---- app/src/main/res/values/settings_keys.xml | 7 ++++--- app/src/main/res/values/strings.xml | 3 ++- app/src/main/res/xml/settings_screen.xml | 11 ++++++++--- 4 files changed, 20 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/ActionBarHandler.java b/app/src/main/java/org/schabi/newpipe/ActionBarHandler.java index 28fbbac37..ab7bcef96 100644 --- a/app/src/main/java/org/schabi/newpipe/ActionBarHandler.java +++ b/app/src/main/java/org/schabi/newpipe/ActionBarHandler.java @@ -139,7 +139,7 @@ class ActionBarHandler { MenuItem castItem = menu.findItem(R.id.action_play_with_kodi); castItem.setVisible(defaultPreferences - .getBoolean(activity.getString(R.string.showPlayWidthKodiPreference), false)); + .getBoolean(activity.getString(R.string.showPlayWithKodiPreference), false)); } public boolean onItemSelected(MenuItem item) { @@ -187,7 +187,7 @@ class ActionBarHandler { // ----------- THE MAGIC MOMENT --------------- if(!videoTitle.isEmpty()) { if (PreferenceManager.getDefaultSharedPreferences(activity) - .getBoolean(activity.getString(R.string.useExternalPlayer), false)) { + .getBoolean(activity.getString(R.string.useExternalVideoPlayer), false)) { // External Player Intent intent = new Intent(); @@ -297,9 +297,11 @@ class ActionBarHandler { } public void playAudio() { - boolean b = true;//todo: replace with preference + + boolean externalAudioPlayer = PreferenceManager.getDefaultSharedPreferences(activity) + .getBoolean(activity.getString(R.string.useExternalAudioPlayer), false); Intent intent; - if (b)//internal (background) music player: explicit intent + if (!externalAudioPlayer)//internal (background) music player: explicit intent { intent = new Intent(activity, BackgroundPlayer.class); diff --git a/app/src/main/res/values/settings_keys.xml b/app/src/main/res/values/settings_keys.xml index f7c6020a6..8d33b8cbe 100644 --- a/app/src/main/res/values/settings_keys.xml +++ b/app/src/main/res/values/settings_keys.xml @@ -6,9 +6,10 @@ settings_category_etc download_path_preference - use_external_player + use_external_video_player + use_external_audio_player autoplay_through_intent - default_resulution_preference + default_resolution_preference 720p 360p @@ -16,7 +17,7 @@ 144p 360p - show_play_with_kodi_preference + show_play_with_kodi_preference default_audio_format @string/webMAudioDescription diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c819f5ff7..611c28def 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -19,7 +19,8 @@ Choose browser: rotation Settings - Use external player + Use external video player + Use external audio (background) player Download location Path to store downloaded videos in. Enter download path diff --git a/app/src/main/res/xml/settings_screen.xml b/app/src/main/res/xml/settings_screen.xml index 724c27e99..98399f778 100644 --- a/app/src/main/res/xml/settings_screen.xml +++ b/app/src/main/res/xml/settings_screen.xml @@ -8,8 +8,13 @@ android:title="@string/settingsCategoryVideoAudioTitle"> + + From 3554ccde0551ed8a75b430b8c3117da0140892a4 Mon Sep 17 00:00:00 2001 From: Christian Schabesberger Date: Sun, 20 Dec 2015 18:15:48 +0100 Subject: [PATCH 12/12] small adjustment before merg --- app/src/main/res/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 611c28def..cf87951b6 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -20,7 +20,7 @@ rotation Settings Use external video player - Use external audio (background) player + Use external audio player Download location Path to store downloaded videos in. Enter download path