mirror of
				https://github.com/TeamNewPipe/NewPipe
				synced 2025-10-31 15:23:00 +00:00 
			
		
		
		
	Implemented a playback notification with a progress bar. No playback controls yet.
This commit is contained in:
		| @@ -72,7 +72,10 @@ | ||||
|             android:parentActivityName=".VideoItemDetailActivity" | ||||
|             > | ||||
|         </activity> | ||||
|         <service android:name=".BackgroundPlayer" | ||||
|         <!--TODO: make label a translatable string --> | ||||
|         <service | ||||
|             android:name=".BackgroundPlayer" | ||||
|             android:label="NewPipe Background Player" | ||||
|             android:exported="false" > | ||||
|         </service> | ||||
|         <activity | ||||
|   | ||||
| @@ -2,6 +2,7 @@ package org.schabi.newpipe; | ||||
|  | ||||
| import android.app.IntentService; | ||||
| import android.app.Notification; | ||||
| import android.app.NotificationManager; | ||||
| import android.app.Service; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| @@ -15,8 +16,10 @@ 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; | ||||
|  | ||||
| @@ -45,11 +48,13 @@ import java.io.IOException; | ||||
| public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPreparedListener*/ { | ||||
|  | ||||
|     private static final String TAG = BackgroundPlayer.class.toString(); | ||||
|     private Looper mServiceLooper; | ||||
|     private ServiceHandler mServiceHandler; | ||||
|     //private Looper mServiceLooper; | ||||
|     //private ServiceHandler mServiceHandler; | ||||
|  | ||||
|     public BackgroundPlayer() { | ||||
|         super(); | ||||
|  | ||||
|         VideoView v; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
| @@ -59,59 +64,69 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare | ||||
|         // 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(); | ||||
|         //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); | ||||
|         //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); | ||||
|         String source = intent.getDataString(); | ||||
|         String videoTitle = intent.getStringExtra("title"); | ||||
|  | ||||
|         // If we get killed, after returning from here, don't restart | ||||
|         PlayerThread player = new PlayerThread(source, videoTitle, this); | ||||
|         player.start(); | ||||
|  | ||||
|         // If we get killed after returning here, don't restart | ||||
|         return START_NOT_STICKY; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public IBinder onBind(Intent intent) { | ||||
|         // We don't provide binding yet, so return null | ||||
|         // 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(); | ||||
|         //mServiceLooper.quit(); | ||||
|         //if (mMediaPlayer != null) mMediaPlayer.release(); | ||||
|         //todo: call MediaPlayer.release() as soon as video is complete | ||||
|     } | ||||
|  | ||||
|     protected void onHandleIntent(Intent intent) { | ||||
|         String source = intent.getDataString(); | ||||
|     private class PlayerThread extends Thread { | ||||
|  | ||||
|         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 | ||||
|         private MediaPlayer mediaPlayer; | ||||
|         private String source; | ||||
|         private String title; | ||||
|         private BackgroundPlayer owner; | ||||
|         public PlayerThread(String src, String title, BackgroundPlayer owner) { | ||||
|             this.source = src; | ||||
|             this.title = title; | ||||
|             this.owner = owner; | ||||
|             mediaPlayer = new MediaPlayer(); | ||||
|             mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); | ||||
|         } | ||||
|         @Override | ||||
|         public void run() { | ||||
|             mediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);//cpu lock | ||||
|             try { | ||||
|                 mediaPlayer.setDataSource(source); | ||||
|             mediaPlayer.prepare(); //IntentService already puts us in a separate worker thread, | ||||
|                 mediaPlayer.prepare(); //We are already in a separate worker thread, | ||||
|                 //so calling the blocking prepare() method should be ok | ||||
|  | ||||
|                 //mediaPlayer.setOnPreparedListener(this); | ||||
|                 //mediaPlayer.prepareAsync(); //prepare async to not block main thread | ||||
|             } catch (IOException ioe) { | ||||
|                 ioe.printStackTrace(); | ||||
|             //can't really do anything useful without a file to play; exit early | ||||
|                 Log.e(TAG, "video source:" + source); | ||||
|                 Log.e(TAG, "video title:" + title); | ||||
|                 //can't do anything useful without a file to play; exit early | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
| @@ -119,43 +134,59 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare | ||||
|             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) | ||||
|             //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); | ||||
|             noteBuilder | ||||
|                     .setPriority(Notification.PRIORITY_LOW) | ||||
|                     .setCategory(Notification.CATEGORY_TRANSPORT) | ||||
|                 .setContentTitle(videoTitle) | ||||
|                 .setContentText("NewPipe is playing in the background")//todo: add translatable string | ||||
|                     .setContentTitle(title) | ||||
|                     .setContentText("NewPipe is playing in the background")//todo: translation string | ||||
|                     .setOngoing(true) | ||||
|                 .setSmallIcon(R.mipmap.ic_launcher) | ||||
|                 .build(); | ||||
|                     .setProgress(vidLength, 0, false) | ||||
|                     .setSmallIcon(R.mipmap.ic_launcher); | ||||
|  | ||||
|         startForeground(TAG.hashCode(), noti); | ||||
|             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)); | ||||
|             while(mediaPlayer.isPlaying()) { | ||||
|                 try { | ||||
|                     Thread.sleep(sleepTime); | ||||
|                 } catch (InterruptedException e) { | ||||
|                     Log.d(TAG, "sleep failure"); | ||||
|                 } | ||||
|                 noteBuilder.setProgress(vidLength, mediaPlayer.getCurrentPosition(), false); | ||||
|                 noteMgr.notify(noteID, noteBuilder.build()); | ||||
|             } | ||||
|             noteBuilder.setProgress(0, 0, false);//remove bar | ||||
|             //noteMgr.notify(0, noteBuilder.build()); | ||||
|         } | ||||
|     } | ||||
| /* | ||||
|     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) { | ||||
| @@ -164,21 +195,10 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare | ||||
|  | ||||
|         @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); | ||||
|             wl.release();//release wifilock | ||||
|             stopForeground(true);//remove ongoing notification | ||||
|             stopSelf(); | ||||
|             //todo:release cpu lock | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Adam Howard
					Adam Howard