Commit 45e62492 authored by hal's avatar hal

Merge pull request #33 from klaverty/player-mods

Updates for the Player component
parents e2ff8ce6 03549640
......@@ -701,6 +701,13 @@ public final class YoungAndroidFormUpgrader {
// No properties need to be modified to upgrade to version 3.
srcCompVersion = 3;
}
if (srcCompVersion < 4) {
// The Looping and Volume properties were added.
// The Completed Event was added.
// The IsPlaying method was added.
// No properties need to be modified to upgrade to version 4.
srcCompVersion = 4;
}
return srcCompVersion;
}
......
......@@ -863,6 +863,13 @@ public class BlockSaveFile {
}
blkCompVersion = 3;
}
if (blkCompVersion < 4) {
// The Looping and Volume properties were added.
// The Completed Event was added.
// The IsPlaying method was added.
// No properties need to be modified to upgrade to version 4.
blkCompVersion = 4;
}
return blkCompVersion;
}
......
......@@ -172,8 +172,10 @@ public class YaVersion {
// - ACCELEROMETERSENSOR_COMPONENT_VERSION was incremented to 2.
// For YOUNG_ANDROID_VERSION 56
// - LOCATIONSENSOR_COMPONENT_VERSION was incremented to 2
// For YOUNG_ANDROID_VERSION 57:
// - PLAYER_COMPONENT_VERSION was incremented to 4.
public static final int YOUNG_ANDROID_VERSION = 56;
public static final int YOUNG_ANDROID_VERSION = 57;
// ............................... Blocks Language Version Number ...............................
......@@ -423,7 +425,13 @@ public class YaVersion {
// - The Player.PlayerError event was added.
// For PLAYER_COMPONENT_VERSION 3:
// - The Player.PlayerError event was marked userVisible false and is no longer used.
public static final int PLAYER_COMPONENT_VERSION = 3;
// For PLAYER_COMPONENT_VERSION 4:
// - The Player.Completed event was added.
// - The IsLooping property was added.
// - The Volume property was added.
// - The IsPlaying method was added.
public static final int PLAYER_COMPONENT_VERSION = 4;
// For SOUND_COMPONENT_VERSION 2:
// - The Sound.SoundError event was added.
......
......@@ -13,12 +13,14 @@ import com.google.appinventor.components.annotations.UsesPermissions;
import com.google.appinventor.components.common.ComponentCategory;
import com.google.appinventor.components.common.PropertyTypeConstants;
import com.google.appinventor.components.common.YaVersion;
import com.google.appinventor.components.runtime.errors.IllegalArgumentError;
import com.google.appinventor.components.runtime.util.ErrorMessages;
import com.google.appinventor.components.runtime.util.MediaUtil;
import android.content.Context;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.os.Vibrator;
import android.util.Log;
......@@ -65,7 +67,7 @@ import java.io.IOException;
@SimpleObject
@UsesPermissions(permissionNames = "android.permission.VIBRATE, android.permission.INTERNET")
public final class Player extends AndroidNonvisibleComponent
implements Component, OnDestroyListener, Deleteable {
implements Component, OnCompletionListener, OnDestroyListener, Deleteable {
private MediaPlayer mp;
private final Vibrator vibe;
......@@ -137,6 +139,7 @@ public final class Player extends AndroidNonvisibleComponent
if (sourcePath.length() > 0) {
Log.i("Player", "Source path is " + sourcePath);
mp = new MediaPlayer();
mp.setOnCompletionListener(this);
try {
MediaUtil.loadMediaPlayer(mp, form, sourcePath);
......@@ -158,9 +161,72 @@ public final class Player extends AndroidNonvisibleComponent
// Player should now be in state 1. (If prepare failed, we are in state 0.)
}
}
/**
* Reports whether the media is playing.
*/
@SimpleProperty(
description = "Whether the media is playing",
category = PropertyCategory.BEHAVIOR)
public boolean IsPlaying() {
if (playerState == 1 || playerState == 2) {
return mp.isPlaying();
}
return false;
}
/**
* Reports whether the media is looping.
*/
@SimpleProperty(
description = "Whether the media is looping",
category = PropertyCategory.BEHAVIOR)
public boolean IsLooping() {
if (playerState == 1 || playerState == 2) {
return mp.isLooping();
}
return false;
}
/**
* Sets the looping property to true or false.
*
* @param looping tells if the media should be looping
*/
@DesignerProperty(
editorType = PropertyTypeConstants.PROPERTY_TYPE_BOOLEAN,
defaultValue = "False")
@SimpleProperty
public void IsLooping(boolean looping) {
if (playerState == 1 || playerState == 2) {
mp.setLooping(looping);
Log.i("Player", "Looping is " + String.valueOf(looping));
}
}
/**
* Sets the volume property to a number between 0 and 100.
*
* @param vol the desired volume level
*/
@DesignerProperty(
editorType = PropertyTypeConstants.PROPERTY_TYPE_NON_NEGATIVE_FLOAT,
defaultValue = "50")
@SimpleProperty(
description = "Sets the volume to a number between 0 and 100")
public void Volume(int vol) {
if (playerState == 1 || playerState == 2) {
if (vol > 100 || vol < 0) {
throw new IllegalArgumentError("Volume must be set to a number between 0 and 100");
}
mp.setVolume(((float) vol)/100, ((float) vol)/100);
Log.i("Player", "Volume is " + String.valueOf(vol));
}
}
/**
* Plays the media. If it was previously paused, the playing is resumed.
* If it was previously stopped, it starts from the beginning.
*/
@SimpleFunction
public void Start() {
......@@ -186,7 +252,7 @@ public final class Player extends AndroidNonvisibleComponent
}
/**
* Stops playing the media
* Stops playing the media and seeks to the beginning of the song.
*/
@SimpleFunction
public void Stop() {
......@@ -194,6 +260,7 @@ public final class Player extends AndroidNonvisibleComponent
if (playerState == 1 || playerState == 2) {
mp.stop();
prepare();
mp.seekTo(0);
// Player should now be in state 1. (If prepare failed, we are in state 0.)
}
}
......@@ -229,7 +296,23 @@ public final class Player extends AndroidNonvisibleComponent
ErrorMessages.ERROR_UNABLE_TO_PREPARE_MEDIA, sourcePath);
}
}
// OnCompletionListener implementation
@Override
public void onCompletion(MediaPlayer m) {
Completed();
}
/**
* Indicates that the media has reached the end
*/
@SimpleEvent
public void Completed() {
Log.i("Player", "Calling Completed -- State=" + playerState);
EventDispatcher.dispatchEvent(this, "Completed");
}
// OnDestroyListener implementation
@Override
......
......@@ -298,9 +298,14 @@
<code>
Source
</code>
property, which can be set in the Designer or in the Blocks Editor. The length of
property, which can be set in the Designer or in the Blocks Editor. To use a Player for
streaming, set the
<code>
Source
</code>
inside the Blocks Editor to a text block with the URL. The length of
time for a vibration is specified in the Blocks Editor in milliseconds (thousandths
of a second).
of a second). The volume should be an integer between 0 and 100.
</p>
<p>
See
......@@ -322,6 +327,22 @@
Properties
</h3>
<dl>
<dt>
<code>
IsLooping
</code>
</dt>
<dd>
If set, the media is looping.
</dd>
<dt>
<code>
IsPlaying
</code>
</dt>
<dd>
Whether the media is playing.
</dd>
<dt>
<code>
Source
......@@ -330,6 +351,14 @@
<dd>
Audio or video file associated with this player.
</dd>
<dt>
<code>
Volume
</code>
</dt>
<dd>
A number between 0 and 100.
</dd>
</dl>
<h3>
Methods
......@@ -368,6 +397,19 @@
Activate the phone's vibration motor for the given number of milliseconds.
</dd>
</dl>
<h3>
Events
</h3>
<dl>
<dt>
<code>
Completed()
</code>
</dt>
<dd>
Media has finished playing.
</dd>
</dl>
<h2 id="Sound">
Sound
</h2>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment