From b55295c7acdb156aedeab456ba02d9aba17d8de1 Mon Sep 17 00:00:00 2001 From: Buddy Reno Date: Mon, 28 Aug 2017 14:42:20 -0500 Subject: [PATCH] Merge PR #137 for android playAudioWhenScreenIsLocked --- src/android/AudioHandler.java | 145 +++++++++++++++++++++++++--------- src/android/AudioPlayer.java | 41 ++++++---- 2 files changed, 133 insertions(+), 53 deletions(-) diff --git a/src/android/AudioHandler.java b/src/android/AudioHandler.java index 9e734c44..2cb8ba7d 100644 --- a/src/android/AudioHandler.java +++ b/src/android/AudioHandler.java @@ -18,29 +18,27 @@ Licensed to the Apache Software Foundation (ASF) under one */ package org.apache.cordova.media; -import org.apache.cordova.CallbackContext; -import org.apache.cordova.CordovaPlugin; -import org.apache.cordova.CordovaResourceApi; import org.apache.cordova.PermissionHelper; - -import android.Manifest; -import android.content.Context; -import android.content.pm.PackageManager; -import android.media.AudioManager; -import android.media.AudioManager.OnAudioFocusChangeListener; -import android.net.Uri; -import android.os.Build; - import java.security.Permission; + import java.util.ArrayList; +import java.util.HashMap; +import org.apache.cordova.CallbackContext; +import org.apache.cordova.CordovaPlugin; +import org.apache.cordova.CordovaResourceApi; import org.apache.cordova.LOG; import org.apache.cordova.PluginResult; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; -import java.util.HashMap; +import android.Manifest; +import android.content.Context; +import android.content.pm.PackageManager; +import android.media.AudioManager; +import android.media.AudioManager.OnAudioFocusChangeListener; +import android.net.Uri; /** * This class called by CordovaActivity to play and record audio. @@ -57,8 +55,10 @@ public class AudioHandler extends CordovaPlugin { public static String TAG = "AudioHandler"; HashMap players; // Audio player object - ArrayList pausedForPhone; // Audio players that were paused when phone call came in - ArrayList pausedForFocus; // Audio players that were paused when focus was lost + ArrayList paused; // Audio players that were paused. Reasons: + boolean audioFocusLost = false; // paused when audiofocus was lost + boolean calling = false; // paused when calling + boolean activityFocusLost = false; // paused when activity got paused private int origVolumeStream = -1; private CallbackContext messageChannel; @@ -77,8 +77,7 @@ public class AudioHandler extends CordovaPlugin { */ public AudioHandler() { this.players = new HashMap(); - this.pausedForPhone = new ArrayList(); - this.pausedForFocus = new ArrayList(); + this.paused = new ArrayList(); } @@ -129,13 +128,20 @@ else if (action.equals("resumeRecordingAudio")) { else if (action.equals("startPlayingAudio")) { String target = args.getString(1); String fileUriStr; + boolean playAudioWhenScreenIsLocked=true; try { Uri targetUri = resourceApi.remapUri(Uri.parse(target)); fileUriStr = targetUri.toString(); } catch (IllegalArgumentException e) { fileUriStr = target; } - this.startPlayingAudio(args.getString(0), FileHelper.stripFileProtocol(fileUriStr)); + try { + JSONObject playArgs = new JSONObject(args.getString(2)); + playAudioWhenScreenIsLocked = playArgs.getBoolean("playAudioWhenScreenIsLocked"); + } catch (JSONException e) { + playAudioWhenScreenIsLocked = true; + } + this.startPlayingAudio(args.getString(0), FileHelper.stripFileProtocol(fileUriStr),playAudioWhenScreenIsLocked); } else if (action.equals("seekToAudio")) { this.seekToAudio(args.getString(0), args.getInt(1)); @@ -225,21 +231,21 @@ public Object onMessage(String id, Object data) { if ("ringing".equals(data) || "offhook".equals(data)) { // Get all audio players and pause them - for (AudioPlayer audio : this.players.values()) { - if (audio.getState() == AudioPlayer.STATE.MEDIA_RUNNING.ordinal()) { - this.pausedForPhone.add(audio); - audio.pausePlaying(); - } - } + calling = true; + pauseAll(); } // If phone idle, then resume playing those players we paused else if ("idle".equals(data)) { - for (AudioPlayer audio : this.pausedForPhone) { - audio.startPlaying(null); - } - this.pausedForPhone.clear(); + if(!audioFocusLost){ + if (activityFocusLost) { + resumePlayingMarked(); + }else { + resumePlayingAll(); + } + } + calling = false; } } return null; @@ -250,14 +256,19 @@ else if ("idle".equals(data)) { //-------------------------------------------------------------------------- private AudioPlayer getOrCreatePlayer(String id, String file) { + return getOrCreatePlayer(id,file,true); + } + + private AudioPlayer getOrCreatePlayer(String id, String file, boolean playAudioWhenScreenIsLocked) { AudioPlayer ret = players.get(id); if (ret == null) { if (players.isEmpty()) { onFirstPlayerCreated(); } - ret = new AudioPlayer(this, id, file); + ret = new AudioPlayer(this, id, file, playAudioWhenScreenIsLocked); players.put(id, ret); } + ret.setPlayAudioWhenScreenIsLocked(playAudioWhenScreenIsLocked); return ret; } @@ -315,8 +326,8 @@ public void resumeRecordingAudio(String id) { * @param id The id of the audio player * @param file The name of the audio file. */ - public void startPlayingAudio(String id, String file) { - AudioPlayer audio = getOrCreatePlayer(id, file); + public void startPlayingAudio(String id, String file, boolean playAudioWhenScreenIsLocked) { + AudioPlayer audio = getOrCreatePlayer(id, file, playAudioWhenScreenIsLocked); audio.startPlaying(file); getAudioFocus(); } @@ -400,22 +411,56 @@ else if (output == 1) { } } - public void pauseAllLostFocus() { + /** + * This method pauses all AudioPlayers. + * */ + public void pauseAll() { for (AudioPlayer audio : this.players.values()) { if (audio.getState() == AudioPlayer.STATE.MEDIA_RUNNING.ordinal()) { - this.pausedForFocus.add(audio); + this.paused.add(audio); audio.pausePlaying(); } } } - public void resumeAllGainedFocus() { - for (AudioPlayer audio : this.pausedForFocus) { + /** + * This method pauses all AudioPlayers not marked with isPlayAudioWhenScreenIsLocked. + * */ + public void pauseAudiosNotMarked() { + for (AudioPlayer audio : this.players.values()) { + if (audio.getState() == AudioPlayer.STATE.MEDIA_RUNNING.ordinal() && !audio.isPlayAudioWhenScreenIsLocked()) { + this.paused.add(audio); + audio.pausePlaying(); + } + } + } + + /** + * Resume playing all paused audios + */ + public void resumePlayingAll() { + for (AudioPlayer audio : this.paused) { audio.resumePlaying(); } - this.pausedForFocus.clear(); + paused.clear(); } + /** + * Resume playing all audios marked with isPlayAudioWhenScreenIsLocked + */ + public void resumePlayingMarked() { + ArrayList remove = new ArrayList(); + for (AudioPlayer audio : this.paused) { + if(audio.isPlayAudioWhenScreenIsLocked()){ + audio.resumePlaying(); + remove.add(audio); + } + } + paused.removeAll(remove); + } + + + /** * Get the the audio focus */ @@ -425,10 +470,18 @@ public void onAudioFocusChange(int focusChange) { case (AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) : case (AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) : case (AudioManager.AUDIOFOCUS_LOSS) : - pauseAllLostFocus(); + pauseAll(); + audioFocusLost = true; break; case (AudioManager.AUDIOFOCUS_GAIN): - resumeAllGainedFocus(); + if (!calling) { + if(activityFocusLost){ + resumePlayingMarked(); + }else{ + resumePlayingAll(); + } + } + audioFocusLost = false; break; default: break; @@ -553,6 +606,22 @@ else if(PermissionHelper.hasPermission(this, permissions[RECORD_AUDIO])) } + @Override + public void onResume(boolean multitasking) { + super.onResume(multitasking); + if (!(audioFocusLost||calling)) { + resumePlayingAll(); + } + activityFocusLost = false; + } + + @Override + public void onPause(boolean multitasking) { + activityFocusLost = true; + pauseAudiosNotMarked(); + super.onPause(multitasking); + } + /** * Get current amplitude of recording. * @param id The id of the audio player diff --git a/src/android/AudioPlayer.java b/src/android/AudioPlayer.java index 861421e7..9ddd3019 100644 --- a/src/android/AudioPlayer.java +++ b/src/android/AudioPlayer.java @@ -18,6 +18,18 @@ Licensed to the Apache Software Foundation (ASF) under one */ package org.apache.cordova.media; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.LinkedList; + +import org.apache.cordova.LOG; +import org.json.JSONException; +import org.json.JSONObject; + import android.media.AudioManager; import android.media.MediaPlayer; import android.media.MediaPlayer.OnCompletionListener; @@ -26,19 +38,6 @@ Licensed to the Apache Software Foundation (ASF) under one import android.media.MediaRecorder; import android.os.Environment; -import org.apache.cordova.LOG; - -import org.json.JSONException; -import org.json.JSONObject; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.IOException; -import java.util.LinkedList; - /** * This class implements the audio playback and recording capabilities used by Cordova. * It is called by the AudioHandler Cordova class. @@ -93,17 +92,29 @@ public enum STATE { MEDIA_NONE, private boolean prepareOnly = true; // playback after file prepare flag private int seekOnPrepared = 0; // seek to this location once media is prepared - /** + private boolean playAudioWhenScreenIsLocked = true; // If set to false the playback will be paused when app is paused + + public boolean isPlayAudioWhenScreenIsLocked() { + return playAudioWhenScreenIsLocked; + } + + public void setPlayAudioWhenScreenIsLocked(boolean playAudioWhenScreenIsLocked) { + this.playAudioWhenScreenIsLocked = playAudioWhenScreenIsLocked; + } + + /** * Constructor. * * @param handler The audio handler object * @param id The id of this audio player */ - public AudioPlayer(AudioHandler handler, String id, String file) { + public AudioPlayer(AudioHandler handler, String id, String file, boolean playAudioWhenScreenIsLocked) { this.handler = handler; this.id = id; this.audioFile = file; this.tempFiles = new LinkedList(); + + this.playAudioWhenScreenIsLocked = playAudioWhenScreenIsLocked; } private String generateTempFile() {