Removed FitnessCycle, reformatted code, made Pepper actions globally accessible
This commit is contained in:
@@ -19,8 +19,7 @@ public enum EMuscleGroup {
|
|||||||
return this.muscleGroupIdentifier;
|
return this.muscleGroupIdentifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static EMuscleGroup parse(String name)
|
public static EMuscleGroup parse(String name) {
|
||||||
{
|
|
||||||
for (EMuscleGroup muscleGroup : EMuscleGroup.values())
|
for (EMuscleGroup muscleGroup : EMuscleGroup.values())
|
||||||
for (String muscleGroupName : muscleGroup.muscleGroupNames)
|
for (String muscleGroupName : muscleGroup.muscleGroupNames)
|
||||||
if (muscleGroupName.equalsIgnoreCase(name))
|
if (muscleGroupName.equalsIgnoreCase(name))
|
||||||
|
@@ -1,12 +1,6 @@
|
|||||||
package com.example.fitbot.exercise;
|
package com.example.fitbot.exercise;
|
||||||
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import com.example.fitbot.util.path.GesturePath;
|
import com.example.fitbot.util.path.GesturePath;
|
||||||
import com.example.fitbot.util.server.IWebServerHandler;
|
|
||||||
import com.example.fitbot.util.server.WebServer;
|
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
public class Exercise {
|
public class Exercise {
|
||||||
|
|
||||||
|
@@ -48,7 +48,6 @@ public class ExerciseManager {
|
|||||||
* @param method The method to use for the request, e.g. GET or POST.
|
* @param method The method to use for the request, e.g. GET or POST.
|
||||||
* @param contentType The content type of the request.
|
* @param contentType The content type of the request.
|
||||||
* @param body The body of the request.
|
* @param body The body of the request.
|
||||||
*
|
|
||||||
* @return The response from the server.
|
* @return The response from the server.
|
||||||
*/
|
*/
|
||||||
public static String sendHTTP(String url, String method, String contentType, String body) {
|
public static String sendHTTP(String url, String method, String contentType, String body) {
|
||||||
|
@@ -1,53 +0,0 @@
|
|||||||
package com.example.fitbot.exercise;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The ExerciseUser class represents a user of the exercise application.
|
|
||||||
* This contains all necessary information of the current user.
|
|
||||||
*/
|
|
||||||
public class ExerciseUser {
|
|
||||||
|
|
||||||
public float upperArmLength;
|
|
||||||
public float lowerArmLength;
|
|
||||||
public float upperLegLength;
|
|
||||||
public float lowerLegLength;
|
|
||||||
public float height;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor for the ExerciseUser class.
|
|
||||||
* @param upperArmLength The length of the upper arm.
|
|
||||||
* @param lowerArmLength The length of the lower arm.
|
|
||||||
* @param height The height of the user.
|
|
||||||
* @param upperLegLength The length of the upper leg.
|
|
||||||
* @param lowerLegLength The length of the lower leg.
|
|
||||||
*/
|
|
||||||
public ExerciseUser(float upperArmLength, float lowerArmLength, float height, float upperLegLength, float lowerLegLength) {
|
|
||||||
this.upperArmLength = upperArmLength;
|
|
||||||
this.lowerArmLength = lowerArmLength;
|
|
||||||
this.upperLegLength = upperLegLength;
|
|
||||||
this.lowerLegLength = lowerLegLength;
|
|
||||||
this.height = height;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor for the ExerciseUser class.
|
|
||||||
* @param height The height of the user.
|
|
||||||
*/
|
|
||||||
public ExerciseUser(float height) {
|
|
||||||
this.height = height;
|
|
||||||
this.upperArmLength = height * 0.2f;
|
|
||||||
this.lowerArmLength = height * 0.2f;
|
|
||||||
this.upperLegLength = height * 0.3f;
|
|
||||||
this.lowerLegLength = height * 0.3f;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default constructor for the ExerciseUser class.
|
|
||||||
* This sets the default height to 180.0f. (1.80m)
|
|
||||||
*/
|
|
||||||
public ExerciseUser() {
|
|
||||||
this(180.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
@@ -1,15 +1,6 @@
|
|||||||
package com.example.fitbot.pepper;
|
package com.example.fitbot.pepper;
|
||||||
|
|
||||||
import com.aldebaran.qi.sdk.QiContext;
|
|
||||||
|
|
||||||
public abstract class AbstractPepperActionEvent {
|
public abstract class AbstractPepperActionEvent {
|
||||||
|
|
||||||
public final QiContext context;
|
|
||||||
|
|
||||||
public AbstractPepperActionEvent(QiContext context)
|
|
||||||
{
|
|
||||||
this.context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract EPepperAction getAction();
|
public abstract EPepperAction getAction();
|
||||||
}
|
}
|
||||||
|
@@ -6,5 +6,5 @@ package com.example.fitbot.pepper;
|
|||||||
public enum EPepperAction {
|
public enum EPepperAction {
|
||||||
ACTION_SPEAK,
|
ACTION_SPEAK,
|
||||||
ACTION_ANIMATE,
|
ACTION_ANIMATE,
|
||||||
NO_ACTION;
|
NO_ACTION
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
package com.example.fitbot.pepper;
|
package com.example.fitbot.pepper;
|
||||||
|
|
||||||
import com.aldebaran.qi.sdk.QiContext;
|
import com.aldebaran.qi.sdk.QiContext;
|
||||||
|
import com.aldebaran.qi.sdk.RobotLifecycleCallbacks;
|
||||||
import com.aldebaran.qi.sdk.object.locale.Language;
|
import com.aldebaran.qi.sdk.object.locale.Language;
|
||||||
import com.aldebaran.qi.sdk.object.locale.Locale;
|
import com.aldebaran.qi.sdk.object.locale.Locale;
|
||||||
import com.aldebaran.qi.sdk.object.locale.Region;
|
import com.aldebaran.qi.sdk.object.locale.Region;
|
||||||
@@ -11,9 +12,16 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
/**
|
/**
|
||||||
* Class representing the Pepper robot.
|
* Class representing the Pepper robot.
|
||||||
* All functionality related to Pepper is implemented in this class.
|
* All functionality related to Pepper is implemented in this class.
|
||||||
|
* <p>
|
||||||
|
* Before any of the functions in this class can be used, the Pepper class needs a QiContext to be
|
||||||
|
* set. This is retrieved in the `onRobotFocusGained` method of the RobotLifecycleCallbacks
|
||||||
|
* interface, and can then provided using the `provideContext` method.
|
||||||
|
* </p>
|
||||||
*/
|
*/
|
||||||
public class Pepper {
|
public class Pepper {
|
||||||
|
|
||||||
|
// Queue containing all Pepper actions that need to be executed
|
||||||
|
// This is to prevent the app from crashing when attempting to perform multiple actions at once
|
||||||
private static final ConcurrentLinkedQueue<AbstractPepperActionEvent> pepperActionEventQueue =
|
private static final ConcurrentLinkedQueue<AbstractPepperActionEvent> pepperActionEventQueue =
|
||||||
new ConcurrentLinkedQueue<>();
|
new ConcurrentLinkedQueue<>();
|
||||||
|
|
||||||
@@ -23,25 +31,31 @@ public class Pepper {
|
|||||||
private static final Locale DEFAULT_LOCALE = new Locale(Language.DUTCH, Region.NETHERLANDS);
|
private static final Locale DEFAULT_LOCALE = new Locale(Language.DUTCH, Region.NETHERLANDS);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Speak a phrase with Pepper.
|
* The latest QiContext used by Pepper.
|
||||||
|
* This can be publicly accessed to get the latest QiContext used by Pepper.
|
||||||
|
*/
|
||||||
|
public static QiContext latestContext = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make the Pepper robot speak a phrase.
|
||||||
|
* This function adds a SpeechEvent to the event queue,
|
||||||
|
* and will speak the phrase once Pepper is ready to process it.
|
||||||
*
|
*
|
||||||
* @param phrase The phrase to speak
|
* @param phrase The phrase to speak
|
||||||
* @param context The QiContext to use
|
|
||||||
*/
|
*/
|
||||||
public static void speak(String phrase, QiContext context)
|
public static void speak(String phrase) {
|
||||||
{
|
addToEventQueue(new PepperSpeechEvent(phrase, DEFAULT_LOCALE));
|
||||||
addToEventQueue(new PepperSpeechEvent(context, phrase, DEFAULT_LOCALE));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Animate Pepper with the given animation.
|
* Make the Pepper robot perform an animation.
|
||||||
|
* This function adds an AnimationEvent to the event queue,
|
||||||
|
* and will perform the animation once Pepper is ready to process it.
|
||||||
*
|
*
|
||||||
* @param animationName The name of the animation to play
|
* @param animationName The name of the animation to play
|
||||||
* @param context The QiContext to use
|
|
||||||
*/
|
*/
|
||||||
public static void animate(String animationName, QiContext context)
|
public static void animate(String animationName) {
|
||||||
{
|
addToEventQueue(new PepperAnimationEvent(animationName));
|
||||||
addToEventQueue(new PepperAnimationEvent(context, animationName));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -50,8 +64,7 @@ public class Pepper {
|
|||||||
*
|
*
|
||||||
* @param event The event to add to the queue
|
* @param event The event to add to the queue
|
||||||
*/
|
*/
|
||||||
public static void addToEventQueue(AbstractPepperActionEvent event)
|
public static void addToEventQueue(AbstractPepperActionEvent event) {
|
||||||
{
|
|
||||||
pepperActionEventQueue.add(event);
|
pepperActionEventQueue.add(event);
|
||||||
processEventQueue();
|
processEventQueue();
|
||||||
}
|
}
|
||||||
@@ -63,17 +76,15 @@ public class Pepper {
|
|||||||
* This prevents multiple actions from being executed at the same time, which can
|
* This prevents multiple actions from being executed at the same time, which can
|
||||||
* cause the application to crash.
|
* cause the application to crash.
|
||||||
*/
|
*/
|
||||||
private static synchronized void processEventQueue()
|
private static synchronized void processEventQueue() {
|
||||||
{
|
if (!pepperActionEventQueue.isEmpty()) {
|
||||||
if (!pepperActionEventQueue.isEmpty())
|
|
||||||
{
|
|
||||||
AbstractPepperActionEvent event = pepperActionEventQueue.poll();
|
AbstractPepperActionEvent event = pepperActionEventQueue.poll();
|
||||||
|
|
||||||
if (event == null)
|
// Prevent null pointer exceptions
|
||||||
|
if (event == null || latestContext == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
switch (event.getAction())
|
switch (event.getAction()) {
|
||||||
{
|
|
||||||
/* Event for speaking a phrase **/
|
/* Event for speaking a phrase **/
|
||||||
case ACTION_SPEAK:
|
case ACTION_SPEAK:
|
||||||
if (!(event instanceof PepperSpeechEvent) || isSpeaking.get())
|
if (!(event instanceof PepperSpeechEvent) || isSpeaking.get())
|
||||||
@@ -81,7 +92,7 @@ public class Pepper {
|
|||||||
PepperSpeechEvent speechEvent = (PepperSpeechEvent) event;
|
PepperSpeechEvent speechEvent = (PepperSpeechEvent) event;
|
||||||
isSpeaking.set(true);
|
isSpeaking.set(true);
|
||||||
speechEvent
|
speechEvent
|
||||||
.sayPhrase()
|
.getSay(latestContext)
|
||||||
.async()
|
.async()
|
||||||
.run()
|
.run()
|
||||||
.andThenConsume(future -> {
|
.andThenConsume(future -> {
|
||||||
@@ -96,7 +107,7 @@ public class Pepper {
|
|||||||
break;
|
break;
|
||||||
PepperAnimationEvent animationEvent = (PepperAnimationEvent) event;
|
PepperAnimationEvent animationEvent = (PepperAnimationEvent) event;
|
||||||
animationEvent
|
animationEvent
|
||||||
.getAnimation()
|
.getAnimation(latestContext)
|
||||||
.async()
|
.async()
|
||||||
.run()
|
.run()
|
||||||
.andThenConsume(future -> {
|
.andThenConsume(future -> {
|
||||||
@@ -105,9 +116,27 @@ public class Pepper {
|
|||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
// Do nothing
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function for providing the latest QiContext to Pepper.
|
||||||
|
*
|
||||||
|
* @param context The QiContext to use.
|
||||||
|
* This can be null if the context is not available.
|
||||||
|
* @param origin The origin of the context.
|
||||||
|
* This parameter is to prevent other classes from
|
||||||
|
* unnecessarily providing a context, or setting
|
||||||
|
* the context to null.
|
||||||
|
*/
|
||||||
|
public static void provideContext(QiContext context, Class<? extends RobotLifecycleCallbacks> origin) {
|
||||||
|
latestContext = context;
|
||||||
|
if (context != null) {
|
||||||
|
processEventQueue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -9,10 +9,27 @@ import com.aldebaran.qi.sdk.object.actuation.Animation;
|
|||||||
public class PepperAnimationEvent extends AbstractPepperActionEvent {
|
public class PepperAnimationEvent extends AbstractPepperActionEvent {
|
||||||
|
|
||||||
public final String animationName;
|
public final String animationName;
|
||||||
|
private final IAnimationCompletedListener onLabelReachedListener;
|
||||||
|
|
||||||
public PepperAnimationEvent(QiContext context, String animationName) {
|
|
||||||
super(context);
|
/**
|
||||||
|
* Constructor for PepperAnimationEvent
|
||||||
|
*
|
||||||
|
* @param animationName The name of the animation to play
|
||||||
|
* @param onLabelReachedListener The listener to call when the animation is completed
|
||||||
|
*/
|
||||||
|
public PepperAnimationEvent(String animationName, IAnimationCompletedListener onLabelReachedListener) {
|
||||||
this.animationName = animationName;
|
this.animationName = animationName;
|
||||||
|
this.onLabelReachedListener = onLabelReachedListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for PepperAnimationEvent
|
||||||
|
*
|
||||||
|
* @param animationName The name of the animation to play
|
||||||
|
*/
|
||||||
|
public PepperAnimationEvent(String animationName) {
|
||||||
|
this(animationName, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -24,14 +41,25 @@ public class PepperAnimationEvent extends AbstractPepperActionEvent {
|
|||||||
* Returns an animation object, which can be used to play the animation
|
* Returns an animation object, which can be used to play the animation
|
||||||
* in the Pepper class.
|
* in the Pepper class.
|
||||||
*/
|
*/
|
||||||
public Animate getAnimation()
|
public Animate getAnimation(QiContext context) {
|
||||||
{
|
Animation animation = AnimationBuilder.with(context)
|
||||||
Animation animation = AnimationBuilder.with(this.context)
|
.withResources(context.getResources().getIdentifier(animationName, "raw", context.getPackageName()))
|
||||||
.withResources(this.context.getResources().getIdentifier(animationName, "raw", this.context.getPackageName()))
|
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
return AnimateBuilder.with(this.context)
|
Animate animate = AnimateBuilder.with(context)
|
||||||
.withAnimation(animation)
|
.withAnimation(animation)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
// Add a listener for when a label is reached
|
||||||
|
animate.addOnLabelReachedListener((label, time) -> {
|
||||||
|
if (onLabelReachedListener != null && "end".equals(label)) {
|
||||||
|
onLabelReachedListener.onComplete();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return animate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IAnimationCompletedListener {
|
||||||
|
void onComplete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -10,9 +10,7 @@ public class PepperSpeechEvent extends AbstractPepperActionEvent {
|
|||||||
public final String phrase;
|
public final String phrase;
|
||||||
public final Locale locale;
|
public final Locale locale;
|
||||||
|
|
||||||
public PepperSpeechEvent(QiContext context, String phrase, Locale locale)
|
public PepperSpeechEvent(String phrase, Locale locale) {
|
||||||
{
|
|
||||||
super(context);
|
|
||||||
this.locale = locale;
|
this.locale = locale;
|
||||||
this.phrase = phrase;
|
this.phrase = phrase;
|
||||||
}
|
}
|
||||||
@@ -25,9 +23,8 @@ public class PepperSpeechEvent extends AbstractPepperActionEvent {
|
|||||||
/**
|
/**
|
||||||
* Returns a Say object, which can then be executed.
|
* Returns a Say object, which can then be executed.
|
||||||
*/
|
*/
|
||||||
public Say sayPhrase()
|
public Say getSay(QiContext context) {
|
||||||
{
|
return SayBuilder.with(context)
|
||||||
return SayBuilder.with(this.context)
|
|
||||||
.withText(this.phrase)
|
.withText(this.phrase)
|
||||||
.withLocale(this.locale)
|
.withLocale(this.locale)
|
||||||
.build();
|
.build();
|
||||||
|
@@ -1,6 +1,9 @@
|
|||||||
package com.example.fitbot.ui.activities;
|
package com.example.fitbot.ui.activities;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
import android.widget.VideoView;
|
import android.widget.VideoView;
|
||||||
|
|
||||||
import com.aldebaran.qi.sdk.QiContext;
|
import com.aldebaran.qi.sdk.QiContext;
|
||||||
@@ -12,9 +15,8 @@ import com.example.fitbot.R;
|
|||||||
import com.example.fitbot.exercise.Exercise;
|
import com.example.fitbot.exercise.Exercise;
|
||||||
import com.example.fitbot.exercise.ExerciseManager;
|
import com.example.fitbot.exercise.ExerciseManager;
|
||||||
import com.example.fitbot.pepper.Pepper;
|
import com.example.fitbot.pepper.Pepper;
|
||||||
import com.example.fitbot.ui.components.PersonalMotionPreviewElement;
|
import com.example.fitbot.ui.components.ExerciseStatusElement;
|
||||||
import com.example.fitbot.util.NavigationManager;
|
import com.example.fitbot.util.NavigationManager;
|
||||||
import com.example.fitbot.util.FitnessCycle;
|
|
||||||
import com.example.fitbot.util.processing.InputProcessor;
|
import com.example.fitbot.util.processing.InputProcessor;
|
||||||
|
|
||||||
import org.joml.Vector3f;
|
import org.joml.Vector3f;
|
||||||
@@ -22,12 +24,10 @@ import org.joml.Vector3f;
|
|||||||
public class FitnessActivity extends RobotActivity implements RobotLifecycleCallbacks {
|
public class FitnessActivity extends RobotActivity implements RobotLifecycleCallbacks {
|
||||||
|
|
||||||
// Private fields for the FitnessActivity class.
|
// Private fields for the FitnessActivity class.
|
||||||
private PersonalMotionPreviewElement personalMotionPreviewElement;
|
private ExerciseStatusElement personalMotionPreviewElement;
|
||||||
private InputProcessor motionProcessor;
|
private InputProcessor motionProcessor;
|
||||||
private Exercise currentExercise;
|
private Exercise currentExercise;
|
||||||
|
|
||||||
private QiContext qiContext;
|
|
||||||
|
|
||||||
// Some nice little messages for the user
|
// Some nice little messages for the user
|
||||||
private static final String[] EXERCISE_NOT_FOUND_MESSAGES = new String[]{
|
private static final String[] EXERCISE_NOT_FOUND_MESSAGES = new String[]{
|
||||||
"Ik heb momenteel helaas wat moeite met het ophalen van oefeningen, sorry.",
|
"Ik heb momenteel helaas wat moeite met het ophalen van oefeningen, sorry.",
|
||||||
@@ -54,17 +54,16 @@ public class FitnessActivity extends RobotActivity implements RobotLifecycleCall
|
|||||||
|
|
||||||
// Find the VideoView by its ID
|
// Find the VideoView by its ID
|
||||||
VideoView videoView = findViewById(R.id.videoView);
|
VideoView videoView = findViewById(R.id.videoView);
|
||||||
FitnessCycle.playVideo(videoView, this);
|
playVideo(videoView, this);
|
||||||
NavigationManager.setupButtonNavigation(this, R.id.homeButtonFitness, MainActivity.class);
|
NavigationManager.setupButtonNavigation(this, R.id.homeButtonFitness, MainActivity.class);
|
||||||
|
|
||||||
NavigationManager.hideSystemUI(this);
|
NavigationManager.hideSystemUI(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRobotFocusGained(QiContext qiContext) {
|
public void onRobotFocusGained(QiContext qiContext) {
|
||||||
this.qiContext = qiContext;
|
|
||||||
// Find the VideoView by its ID
|
// Provide the context so that all queued actions can be performed.
|
||||||
// CompletableFuture.runAsync(() -> FitnessCycle.executeMovement("bicepcurl", 10, qiContext));
|
Pepper.provideContext(qiContext, this.getClass());
|
||||||
|
|
||||||
personalMotionPreviewElement = findViewById(R.id.personalMotionPreviewElement);
|
personalMotionPreviewElement = findViewById(R.id.personalMotionPreviewElement);
|
||||||
|
|
||||||
@@ -78,15 +77,14 @@ public class FitnessActivity extends RobotActivity implements RobotLifecycleCall
|
|||||||
|
|
||||||
motionProcessor = new InputProcessor(vectors, exercise.exerciseTimeInSeconds, SENSOR_SAMPLE_RATE);
|
motionProcessor = new InputProcessor(vectors, exercise.exerciseTimeInSeconds, SENSOR_SAMPLE_RATE);
|
||||||
|
|
||||||
personalMotionPreviewElement.provideQiContext(qiContext);
|
|
||||||
personalMotionPreviewElement.initialize(exercise, motionProcessor, EXERCISE_COUNT);
|
personalMotionPreviewElement.initialize(exercise, motionProcessor, EXERCISE_COUNT);
|
||||||
|
|
||||||
motionProcessor.startListening();
|
motionProcessor.startListening();
|
||||||
motionProcessor.setInputHandler(personalMotionPreviewElement);
|
motionProcessor.setInputHandler(personalMotionPreviewElement);
|
||||||
}, (n) -> {
|
}, (n) -> {
|
||||||
int randomMessageIndex = (int) Math.floor(Math.random() * EXERCISE_NOT_FOUND_MESSAGES.length);
|
int randomMessageIndex = (int) Math.floor(Math.random() * EXERCISE_NOT_FOUND_MESSAGES.length);
|
||||||
Pepper.speak(EXERCISE_NOT_FOUND_MESSAGES[randomMessageIndex], qiContext);
|
Pepper.speak(EXERCISE_NOT_FOUND_MESSAGES[randomMessageIndex]);
|
||||||
Pepper.speak(EXERCISE_NOT_FOUND_SEEK_HELP_MESSAGE, qiContext);
|
Pepper.speak(EXERCISE_NOT_FOUND_SEEK_HELP_MESSAGE);
|
||||||
NavigationManager.navigateToActivity(this, MainActivity.class);
|
NavigationManager.navigateToActivity(this, MainActivity.class);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -104,25 +102,49 @@ public class FitnessActivity extends RobotActivity implements RobotLifecycleCall
|
|||||||
// therefore we'll have to do it like this...
|
// therefore we'll have to do it like this...
|
||||||
(new Thread(() -> {
|
(new Thread(() -> {
|
||||||
Exercise exercise = ExerciseManager.retrieveExercise();
|
Exercise exercise = ExerciseManager.retrieveExercise();
|
||||||
if ( exercise == null)
|
if (exercise == null) {
|
||||||
{
|
|
||||||
onFailedFetch.handle(null);
|
onFailedFetch.handle(null);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
onSuccessfulFetch.handle(exercise);
|
onSuccessfulFetch.handle(exercise);
|
||||||
}
|
}
|
||||||
})).start();
|
})).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function for playing a video in a VideoView
|
||||||
|
*
|
||||||
|
* @param videoView The VideoView to play the video in
|
||||||
|
* @param context The context to use
|
||||||
|
*/
|
||||||
|
public static void playVideo(VideoView videoView, Context context) {
|
||||||
|
// Set up the video player
|
||||||
|
if (videoView != null) {
|
||||||
|
Uri videoUri = Uri.parse("android.resource://" + context.getPackageName() + "/" + R.raw.bicepvideo);
|
||||||
|
videoView.setVideoURI(videoUri);
|
||||||
|
|
||||||
|
videoView.setOnCompletionListener(mp -> {
|
||||||
|
// Repeat the video when it finishes playing
|
||||||
|
videoView.start();
|
||||||
|
});
|
||||||
|
|
||||||
|
videoView.start();
|
||||||
|
} else {
|
||||||
|
Log.e("FitnessActivity", "VideoView is null. Check your layout XML.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRobotFocusLost() {
|
public void onRobotFocusLost() {
|
||||||
QiSDK.unregister(this, this);
|
QiSDK.unregister(this, this);
|
||||||
|
Pepper.provideContext(null, this.getClass()); // Remove the context (unavailable)
|
||||||
|
|
||||||
// Go to the main screen
|
// Go to the main screen
|
||||||
NavigationManager.navigateToActivity(this, MainActivity.class);
|
NavigationManager.navigateToActivity(this, MainActivity.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRobotFocusRefused(String reason) {}
|
public void onRobotFocusRefused(String reason) {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDestroy() {
|
protected void onDestroy() {
|
||||||
@@ -131,6 +153,8 @@ public class FitnessActivity extends RobotActivity implements RobotLifecycleCall
|
|||||||
this.motionProcessor = null;
|
this.motionProcessor = null;
|
||||||
}
|
}
|
||||||
QiSDK.unregister(this, this);
|
QiSDK.unregister(this, this);
|
||||||
|
Pepper.provideContext(null, this.getClass());
|
||||||
|
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,9 +1,7 @@
|
|||||||
package com.example.fitbot.ui.activities;
|
package com.example.fitbot.ui.activities;
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.support.v7.app.AppCompatActivity;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.View;
|
import android.support.v7.app.AppCompatActivity;
|
||||||
|
|
||||||
import com.example.fitbot.R;
|
import com.example.fitbot.R;
|
||||||
import com.example.fitbot.util.NavigationManager;
|
import com.example.fitbot.util.NavigationManager;
|
||||||
|
@@ -9,13 +9,12 @@ import android.util.AttributeSet;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import com.aldebaran.qi.sdk.QiContext;
|
|
||||||
import com.example.fitbot.exercise.Exercise;
|
import com.example.fitbot.exercise.Exercise;
|
||||||
|
import com.example.fitbot.pepper.Pepper;
|
||||||
import com.example.fitbot.ui.activities.EndScreenActivity;
|
import com.example.fitbot.ui.activities.EndScreenActivity;
|
||||||
import com.example.fitbot.ui.activities.FitnessActivity;
|
import com.example.fitbot.ui.activities.FitnessActivity;
|
||||||
import com.example.fitbot.ui.activities.MainActivity;
|
import com.example.fitbot.ui.activities.MainActivity;
|
||||||
import com.example.fitbot.util.NavigationManager;
|
import com.example.fitbot.util.NavigationManager;
|
||||||
import com.example.fitbot.util.FitnessCycle;
|
|
||||||
import com.example.fitbot.util.processing.IInputHandler;
|
import com.example.fitbot.util.processing.IInputHandler;
|
||||||
import com.example.fitbot.util.processing.InputProcessor;
|
import com.example.fitbot.util.processing.InputProcessor;
|
||||||
|
|
||||||
@@ -26,12 +25,11 @@ import org.joml.Vector4f;
|
|||||||
|
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
|
|
||||||
public class PersonalMotionPreviewElement extends View implements IInputHandler {
|
public class ExerciseStatusElement extends View implements IInputHandler {
|
||||||
|
|
||||||
// Fields regarding Exercise and speech handling.
|
// Fields regarding Exercise and speech handling.
|
||||||
private InputProcessor motionProcessor;
|
private InputProcessor motionProcessor;
|
||||||
private Exercise exercise;
|
private Exercise exercise;
|
||||||
private QiContext qiContext;
|
|
||||||
private int exerciseCount;
|
private int exerciseCount;
|
||||||
|
|
||||||
private FitnessActivity parentActivity;
|
private FitnessActivity parentActivity;
|
||||||
@@ -41,10 +39,10 @@ public class PersonalMotionPreviewElement extends View implements IInputHandler
|
|||||||
private final Paint backgroundPaint = new Paint();
|
private final Paint backgroundPaint = new Paint();
|
||||||
|
|
||||||
// TODO: Remove
|
// TODO: Remove
|
||||||
private Matrix4f viewMatrix = new Matrix4f(); // The view matrix for the 3D to 2D transformation.
|
private final Matrix4f viewMatrix = new Matrix4f(); // The view matrix for the 3D to 2D transformation.
|
||||||
private Matrix4f projectionMatrix = new Matrix4f(); // The projection matrix for the 3D to 2D transformation.
|
private final Matrix4f projectionMatrix = new Matrix4f(); // The projection matrix for the 3D to 2D transformation.
|
||||||
private final Vector4f objectPosition = new Vector4f(0, 0, 0, 1); // The location of the object in 3D space.
|
private final Vector4f objectPosition = new Vector4f(0, 0, 0, 1); // The location of the object in 3D space.
|
||||||
private ConcurrentLinkedQueue<Vector2f> vectors = new ConcurrentLinkedQueue<>();
|
private final ConcurrentLinkedQueue<Vector2f> vectors = new ConcurrentLinkedQueue<>();
|
||||||
|
|
||||||
// TODO: Remove
|
// TODO: Remove
|
||||||
private Vector2f[] axisVectors = new Vector2f[0];
|
private Vector2f[] axisVectors = new Vector2f[0];
|
||||||
@@ -57,11 +55,10 @@ public class PersonalMotionPreviewElement extends View implements IInputHandler
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
public PersonalMotionPreviewElement(Context context, AttributeSet attrs) {
|
public ExerciseStatusElement(Context context, AttributeSet attrs) {
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
|
|
||||||
if ( context instanceof Activity)
|
if (context instanceof Activity) {
|
||||||
{
|
|
||||||
this.parentActivity = (FitnessActivity) context;
|
this.parentActivity = (FitnessActivity) context;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,7 +93,7 @@ public class PersonalMotionPreviewElement extends View implements IInputHandler
|
|||||||
this.exercise = exercise;
|
this.exercise = exercise;
|
||||||
this.exerciseCount = exerciseCount;
|
this.exerciseCount = exerciseCount;
|
||||||
|
|
||||||
// TODO: Remove
|
/* TODO: Remove */
|
||||||
this.axisVectors = new Vector2f[]{
|
this.axisVectors = new Vector2f[]{
|
||||||
projectVertex(new Vector3f(-5.0f, 0, 0), getWidth(), getHeight()),
|
projectVertex(new Vector3f(-5.0f, 0, 0), getWidth(), getHeight()),
|
||||||
projectVertex(new Vector3f(5.0f, 0, 0), getWidth(), getHeight()),
|
projectVertex(new Vector3f(5.0f, 0, 0), getWidth(), getHeight()),
|
||||||
@@ -106,25 +103,24 @@ public class PersonalMotionPreviewElement extends View implements IInputHandler
|
|||||||
projectVertex(new Vector3f(0, 0, 5.0f), getWidth(), getHeight())
|
projectVertex(new Vector3f(0, 0, 5.0f), getWidth(), getHeight())
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Pepper.speak(STARTING_PHRASES[(int) Math.floor(Math.random() * STARTING_PHRASES.length)]);
|
||||||
|
|
||||||
// Handler that is called every time the motion processor receives new data.
|
// Handler that is called every time the motion processor receives new data.
|
||||||
this.motionProcessor.setInputHandler((rotationVector, deviceId) -> {
|
this.motionProcessor.setInputHandler((rotationVector, deviceId) -> {
|
||||||
|
|
||||||
Log.i("MotionProcessor", "Rotation vector received: " + rotationVector);
|
Log.i("MotionProcessor", "Rotation vector received: " + rotationVector);
|
||||||
Log.i("MotionProcessor", "Last error offset:" + this.motionProcessor.getError(deviceId, this.motionProcessor.secondsPassed()));
|
Log.i("MotionProcessor", "Last error offset:" + this.motionProcessor.getError(deviceId, this.motionProcessor.secondsPassed()));
|
||||||
|
|
||||||
if ( this.motionProcessor.hasFinished())
|
if (this.motionProcessor.hasFinished()) {
|
||||||
{
|
|
||||||
// If for some reason the parent activity is not defined,
|
// If for some reason the parent activity is not defined,
|
||||||
// move back to the main screen.
|
// move back to the main screen.
|
||||||
if ( this.parentActivity == null)
|
if (this.parentActivity == null) {
|
||||||
{
|
|
||||||
// Move to main screen
|
// Move to main screen
|
||||||
NavigationManager.navigateToActivity(getContext(), MainActivity.class);
|
NavigationManager.navigateToActivity(getContext(), MainActivity.class);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Move on to the next exercise, or finish.
|
// Move on to the next exercise, or finish.
|
||||||
if ( this.exerciseCount > 0 )
|
if (this.exerciseCount > 0) {
|
||||||
{
|
|
||||||
this.exerciseCount--;
|
this.exerciseCount--;
|
||||||
this.parentActivity.acquireExercise((newExercise) -> {
|
this.parentActivity.acquireExercise((newExercise) -> {
|
||||||
this.motionProcessor.useExercise(newExercise);
|
this.motionProcessor.useExercise(newExercise);
|
||||||
@@ -132,43 +128,27 @@ public class PersonalMotionPreviewElement extends View implements IInputHandler
|
|||||||
// Move to main screen
|
// Move to main screen
|
||||||
NavigationManager.navigateToActivity(parentActivity, MainActivity.class);
|
NavigationManager.navigateToActivity(parentActivity, MainActivity.class);
|
||||||
});
|
});
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
// Finish the exercise.
|
// Finish the exercise.
|
||||||
NavigationManager.navigateToActivity(parentActivity, EndScreenActivity.class);
|
NavigationManager.navigateToActivity(parentActivity, EndScreenActivity.class);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Adjust / remove
|
/* TODO: Use raw vector */
|
||||||
vectors.add(projectVertex(rotationVector, this.getWidth(), this.getHeight()));
|
vectors.add(projectVertex(rotationVector, this.getWidth(), this.getHeight()));
|
||||||
Log.i("MotionProcessor", "Rotation vector received: " + rotationVector);
|
|
||||||
|
/* TODO: Remove */
|
||||||
Vector2f parsed = projectVertex(rotationVector, this.getWidth(), this.getHeight());
|
Vector2f parsed = projectVertex(rotationVector, this.getWidth(), this.getHeight());
|
||||||
|
|
||||||
this.vectors.add(parsed);
|
this.vectors.add(parsed /* TODO: Add regular vertex once exercise data is stored in DB*/);
|
||||||
|
|
||||||
// Remove the first element if the array is too big
|
// Remove the first element if the array is too big
|
||||||
if (this.vectors.size() > 100)
|
if (this.vectors.size() > 100)
|
||||||
this.vectors.poll();
|
this.vectors.poll();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Function for providing a QiContext to the PersonalMotionPreviewElement.
|
|
||||||
* This function will be called by the parent activity when the QiContext is available.
|
|
||||||
* Also say something nice to the user :)
|
|
||||||
*
|
|
||||||
* @param context The QiContext to provide.
|
|
||||||
*/
|
|
||||||
public void provideQiContext(QiContext context) {
|
|
||||||
this.qiContext = context;
|
|
||||||
|
|
||||||
if (this.qiContext == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
FitnessCycle.say(STARTING_PHRASES[(int) Math.floor(Math.random() * STARTING_PHRASES.length)], this.qiContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method for setting the gesture path that will be drawn on the canvas.
|
* Method for setting the gesture path that will be drawn on the canvas.
|
||||||
*
|
*
|
||||||
@@ -203,7 +183,6 @@ public class PersonalMotionPreviewElement extends View implements IInputHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDraw(Canvas canvas) {
|
public void onDraw(Canvas canvas) {
|
||||||
canvas.drawRect(0, 0, getWidth(), getHeight(), backgroundPaint);
|
canvas.drawRect(0, 0, getWidth(), getHeight(), backgroundPaint);
|
||||||
@@ -211,8 +190,9 @@ public class PersonalMotionPreviewElement extends View implements IInputHandler
|
|||||||
/*if (this.exercise == null)
|
/*if (this.exercise == null)
|
||||||
return;*/
|
return;*/
|
||||||
|
|
||||||
for (int i = 0, startX, endX, startY, endY; i < axisVectors.length/2; i++)
|
|
||||||
{
|
/* TODO: Remove */
|
||||||
|
for (int i = 0, startX, endX, startY, endY; i < axisVectors.length / 2; i++) {
|
||||||
startX = (int) Math.max(0, Math.min(this.getWidth(), (int) axisVectors[i * 2].x));
|
startX = (int) Math.max(0, Math.min(this.getWidth(), (int) axisVectors[i * 2].x));
|
||||||
endX = (int) Math.max(0, Math.min(this.getWidth(), (int) axisVectors[i * 2 + 1].x));
|
endX = (int) Math.max(0, Math.min(this.getWidth(), (int) axisVectors[i * 2 + 1].x));
|
||||||
startY = (int) Math.max(0, Math.min(this.getHeight(), (int) axisVectors[i * 2].y));
|
startY = (int) Math.max(0, Math.min(this.getHeight(), (int) axisVectors[i * 2].y));
|
||||||
@@ -220,8 +200,7 @@ public class PersonalMotionPreviewElement extends View implements IInputHandler
|
|||||||
canvas.drawLine(startX, startY, endX, endY, this.borderPaint);
|
canvas.drawLine(startX, startY, endX, endY, this.borderPaint);
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( Vector2f point : this.vectors)
|
for (Vector2f point : this.vectors) {
|
||||||
{
|
|
||||||
canvas.drawRect(point.x, point.y, point.x + 5, point.y + 5, this.userProgressPaint);
|
canvas.drawRect(point.x, point.y, point.x + 5, point.y + 5, this.userProgressPaint);
|
||||||
}
|
}
|
||||||
/*
|
/*
|
@@ -11,8 +11,7 @@ import com.aldebaran.qi.sdk.object.actuation.Animation;
|
|||||||
|
|
||||||
public class Animations {
|
public class Animations {
|
||||||
|
|
||||||
public static void Animate(String AnimationFile, QiContext ctx)
|
public static void Animate(String AnimationFile, QiContext ctx) {
|
||||||
{
|
|
||||||
int resId = ctx.getResources().getIdentifier(AnimationFile, "raw", ctx.getPackageName());
|
int resId = ctx.getResources().getIdentifier(AnimationFile, "raw", ctx.getPackageName());
|
||||||
|
|
||||||
Animation animation = AnimationBuilder.with(ctx)
|
Animation animation = AnimationBuilder.with(ctx)
|
||||||
|
@@ -1,164 +0,0 @@
|
|||||||
package com.example.fitbot.util;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.support.v7.app.AppCompatActivity;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.widget.VideoView;
|
|
||||||
|
|
||||||
import com.aldebaran.qi.sdk.builder.SayBuilder;
|
|
||||||
import com.aldebaran.qi.sdk.object.conversation.Phrase;
|
|
||||||
import com.aldebaran.qi.sdk.object.conversation.Say;
|
|
||||||
import com.aldebaran.qi.sdk.object.locale.Language;
|
|
||||||
import com.aldebaran.qi.sdk.object.locale.Locale;
|
|
||||||
import com.aldebaran.qi.sdk.object.locale.Region;
|
|
||||||
import com.example.fitbot.R;
|
|
||||||
import com.aldebaran.qi.sdk.QiContext;
|
|
||||||
import com.aldebaran.qi.sdk.builder.AnimateBuilder;
|
|
||||||
import com.aldebaran.qi.sdk.builder.AnimationBuilder;
|
|
||||||
import com.aldebaran.qi.sdk.object.actuation.Animate;
|
|
||||||
import com.aldebaran.qi.sdk.object.actuation.Animation;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.BlockingQueue;
|
|
||||||
import java.util.concurrent.LinkedBlockingDeque;
|
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
|
|
||||||
public class FitnessCycle extends AppCompatActivity {
|
|
||||||
|
|
||||||
private static final Locale DUTCH_LOCALE = new Locale(Language.DUTCH, Region.NETHERLANDS);
|
|
||||||
private static final BlockingQueue<PepperSpeechEntry> MESSAGE_QUEUE = new LinkedBlockingQueue<>();
|
|
||||||
private static boolean SPEECH_ACTIVE = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function for executing a movement animation a certain number of times
|
|
||||||
* on the robot
|
|
||||||
*
|
|
||||||
* @param Exercise The name of the exercise to perform
|
|
||||||
* @param Reps The number of repetitions to perform
|
|
||||||
* @param qiContext The QiContext to use
|
|
||||||
*/
|
|
||||||
public static void executeMovement(String Exercise, int Reps, QiContext qiContext) {
|
|
||||||
AtomicInteger repCount = new AtomicInteger(0);
|
|
||||||
|
|
||||||
Animation animation = AnimationBuilder.with(qiContext)
|
|
||||||
.withResources(qiContext.getResources().getIdentifier(Exercise, "raw", qiContext.getPackageName()))
|
|
||||||
.build();
|
|
||||||
|
|
||||||
Animate animate = AnimateBuilder.with(qiContext)
|
|
||||||
.withAnimation(animation)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
// Add a listener for when a label is reached
|
|
||||||
animate.addOnLabelReachedListener((label, time) -> {
|
|
||||||
// Increment repCount when the end of a repetition is reached
|
|
||||||
if ("end".equals(label)) {
|
|
||||||
repCount.incrementAndGet();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Run the animation the desired number of times
|
|
||||||
for (int i = 0; i < Reps; i++) {
|
|
||||||
animate.run();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function for making the robot say something with DUTCH_LOCALE as locale
|
|
||||||
*
|
|
||||||
* @param phrase The phrase to make the robot say
|
|
||||||
* @param ctx The QiContext to use
|
|
||||||
*/
|
|
||||||
public static void say(String phrase, QiContext ctx) {
|
|
||||||
say(phrase, ctx, DUTCH_LOCALE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function for making the robot say something with a specific locale
|
|
||||||
*
|
|
||||||
* @param phrase The phrase to make the robot say
|
|
||||||
* @param ctx The QiContext to use
|
|
||||||
* @param locale The locale to use
|
|
||||||
*/
|
|
||||||
public static void say(String phrase, QiContext ctx, Locale locale) {
|
|
||||||
// If the robot is already speaking, add the phrase to the queue
|
|
||||||
MESSAGE_QUEUE.add(new PepperSpeechEntry(phrase, ctx, locale));
|
|
||||||
processMessageQueue();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static synchronized void processMessageQueue() {
|
|
||||||
if (SPEECH_ACTIVE)
|
|
||||||
return;
|
|
||||||
PepperSpeechEntry nextPhrase = MESSAGE_QUEUE.poll();
|
|
||||||
if (nextPhrase != null) {
|
|
||||||
SPEECH_ACTIVE = true;
|
|
||||||
Say say = nextPhrase.getSay();
|
|
||||||
say.async().run().andThenConsume(future -> {
|
|
||||||
SPEECH_ACTIVE = false;
|
|
||||||
processMessageQueue(); // Process next item in the queue
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function for playing a video in a VideoView
|
|
||||||
*
|
|
||||||
* @param videoView The VideoView to play the video in
|
|
||||||
* @param context The context to use
|
|
||||||
*/
|
|
||||||
public static void playVideo(VideoView videoView, Context context) {
|
|
||||||
// Set up the video player
|
|
||||||
if (videoView != null) {
|
|
||||||
Uri videoUri = Uri.parse("android.resource://" + context.getPackageName() + "/" + R.raw.bicepvideo);
|
|
||||||
videoView.setVideoURI(videoUri);
|
|
||||||
|
|
||||||
videoView.setOnCompletionListener(mp -> {
|
|
||||||
// Repeat the video when it finishes playing
|
|
||||||
videoView.start();
|
|
||||||
});
|
|
||||||
|
|
||||||
videoView.start();
|
|
||||||
} else {
|
|
||||||
Log.e("FitnessActivity", "VideoView is null. Check your layout XML.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class PepperAnimateEvent extends PepperActionEvent {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class PepperSpeechEntry extends PepperActionEvent {
|
|
||||||
public String phrase;
|
|
||||||
public QiContext context;
|
|
||||||
public Locale locale;
|
|
||||||
|
|
||||||
public PepperSpeechEntry(String phrase, QiContext context, Locale locale) {
|
|
||||||
this.action = PepperAction.SPEAK;
|
|
||||||
this.data = this;
|
|
||||||
this.phrase = phrase;
|
|
||||||
this.context = context;
|
|
||||||
this.locale = locale;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Say getSay() {
|
|
||||||
return SayBuilder
|
|
||||||
.with(context)
|
|
||||||
.withLocale(locale)
|
|
||||||
.withText(phrase)
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private enum PepperAction {
|
|
||||||
SPEAK,
|
|
||||||
ANIMATE,
|
|
||||||
MOVE
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class PepperActionEvent {
|
|
||||||
public PepperAction action;
|
|
||||||
public Object data;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -6,10 +6,6 @@ import android.content.Intent;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
|
|
||||||
import com.example.fitbot.ui.activities.FitnessActivity;
|
|
||||||
import com.example.fitbot.ui.activities.MainActivity;
|
|
||||||
import com.example.fitbot.ui.activities.HelpActivity;
|
|
||||||
|
|
||||||
public class NavigationManager {
|
public class NavigationManager {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -21,8 +17,7 @@ public class NavigationManager {
|
|||||||
*/
|
*/
|
||||||
public static void setupButtonNavigation(Activity currentActivity, int buttonId, Class<? extends Activity> targetActivity) {
|
public static void setupButtonNavigation(Activity currentActivity, int buttonId, Class<? extends Activity> targetActivity) {
|
||||||
Button button = currentActivity.findViewById(buttonId);
|
Button button = currentActivity.findViewById(buttonId);
|
||||||
if ( button == null )
|
if (button == null) {
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("Button with ID " + buttonId + " not found in " + currentActivity.getClass().getSimpleName());
|
throw new IllegalArgumentException("Button with ID " + buttonId + " not found in " + currentActivity.getClass().getSimpleName());
|
||||||
}
|
}
|
||||||
button.setOnClickListener(v -> NavigationManager.navigateToActivity(currentActivity, targetActivity));
|
button.setOnClickListener(v -> NavigationManager.navigateToActivity(currentActivity, targetActivity));
|
||||||
|
@@ -2,10 +2,6 @@ package com.example.fitbot.util.path;
|
|||||||
|
|
||||||
import org.joml.Vector3f;
|
import org.joml.Vector3f;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class GesturePath {
|
public class GesturePath {
|
||||||
|
|
||||||
// The vectors that make up the path.
|
// The vectors that make up the path.
|
||||||
@@ -16,8 +12,7 @@ public class GesturePath {
|
|||||||
*
|
*
|
||||||
* @param vectors The vectors that make up the path.
|
* @param vectors The vectors that make up the path.
|
||||||
*/
|
*/
|
||||||
public GesturePath(Vector3f[] vectors)
|
public GesturePath(Vector3f[] vectors) {
|
||||||
{
|
|
||||||
if (vectors.length < 2)
|
if (vectors.length < 2)
|
||||||
throw new IllegalArgumentException("A path must have at least two points.");
|
throw new IllegalArgumentException("A path must have at least two points.");
|
||||||
|
|
||||||
@@ -28,6 +23,7 @@ public class GesturePath {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for a GesturePath with provided PathSegments.
|
* Constructor for a GesturePath with provided PathSegments.
|
||||||
|
*
|
||||||
* @param segments The PathSegments to initialize the path with.
|
* @param segments The PathSegments to initialize the path with.
|
||||||
*/
|
*/
|
||||||
public GesturePath(PathSegment... segments) {
|
public GesturePath(PathSegment... segments) {
|
||||||
@@ -46,8 +42,7 @@ public class GesturePath {
|
|||||||
/**
|
/**
|
||||||
* Method for retrieving the vectors of the GesturePath.
|
* Method for retrieving the vectors of the GesturePath.
|
||||||
*/
|
*/
|
||||||
public Vector3f[] getVectors()
|
public Vector3f[] getVectors() {
|
||||||
{
|
|
||||||
Vector3f[] vectors = new Vector3f[segments.length + 1];
|
Vector3f[] vectors = new Vector3f[segments.length + 1];
|
||||||
vectors[0] = segments[0].getStart();
|
vectors[0] = segments[0].getStart();
|
||||||
for (int i = 0; i < segments.length; i++)
|
for (int i = 0; i < segments.length; i++)
|
||||||
@@ -89,7 +84,7 @@ public class GesturePath {
|
|||||||
* Function for converting a string to a GesturePath object.
|
* Function for converting a string to a GesturePath object.
|
||||||
* The input string bytes will be directly converted into 3d vectors.
|
* The input string bytes will be directly converted into 3d vectors.
|
||||||
* Every scalar is composed of 32 bits (4 characters), meaning 96 bits per vector.
|
* Every scalar is composed of 32 bits (4 characters), meaning 96 bits per vector.
|
||||||
*
|
* <p>
|
||||||
* Note: ASCII to Vector conversion is done in Big Endian format (most significant byte first).
|
* Note: ASCII to Vector conversion is done in Big Endian format (most significant byte first).
|
||||||
*
|
*
|
||||||
* @param input The string to convert
|
* @param input The string to convert
|
||||||
|
@@ -6,6 +6,7 @@ public interface IInputHandler {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Function for accepting motion data and the transformed vector.
|
* Function for accepting motion data and the transformed vector.
|
||||||
|
*
|
||||||
* @param rotationVector The rotation vector of the motion data.
|
* @param rotationVector The rotation vector of the motion data.
|
||||||
* @param sensorId The sensor ID of the motion data.
|
* @param sensorId The sensor ID of the motion data.
|
||||||
*/
|
*/
|
||||||
|
@@ -49,6 +49,7 @@ public class InputProcessor {
|
|||||||
* Function for setting the exercise to use.
|
* Function for setting the exercise to use.
|
||||||
* This updates the user and target path and the
|
* This updates the user and target path and the
|
||||||
* duration of the exercise.
|
* duration of the exercise.
|
||||||
|
*
|
||||||
* @param exercise The exercise to use the paths for.
|
* @param exercise The exercise to use the paths for.
|
||||||
*/
|
*/
|
||||||
public void useExercise(Exercise exercise) {
|
public void useExercise(Exercise exercise) {
|
||||||
@@ -61,6 +62,7 @@ public class InputProcessor {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Function for checking if the exercise has finished.
|
* Function for checking if the exercise has finished.
|
||||||
|
*
|
||||||
* @return True if the exercise has finished, false otherwise.
|
* @return True if the exercise has finished, false otherwise.
|
||||||
*/
|
*/
|
||||||
public boolean hasFinished() {
|
public boolean hasFinished() {
|
||||||
@@ -171,8 +173,7 @@ public class InputProcessor {
|
|||||||
*
|
*
|
||||||
* @return The current progress of the exercise.
|
* @return The current progress of the exercise.
|
||||||
*/
|
*/
|
||||||
public double getCurrentProgress()
|
public double getCurrentProgress() {
|
||||||
{
|
|
||||||
return secondsPassed / exerciseDuration;
|
return secondsPassed / exerciseDuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,8 +209,7 @@ public class InputProcessor {
|
|||||||
|
|
||||||
// Ensure the indexes are within the bounds of the array
|
// Ensure the indexes are within the bounds of the array
|
||||||
if (targetIndex >= 0 && targetIndex <= this.targetRotationVectorPaths[sensorId].length - 1 &&
|
if (targetIndex >= 0 && targetIndex <= this.targetRotationVectorPaths[sensorId].length - 1 &&
|
||||||
selfIndex >= 0 && selfIndex <= this.selfRotationVectorPaths[sensorId].length - 1)
|
selfIndex >= 0 && selfIndex <= this.selfRotationVectorPaths[sensorId].length - 1) {
|
||||||
{
|
|
||||||
return this.selfRotationVectorPaths[sensorId][selfIndex].distance(this.targetRotationVectorPaths[sensorId][targetIndex]);
|
return this.selfRotationVectorPaths[sensorId][selfIndex].distance(this.targetRotationVectorPaths[sensorId][targetIndex]);
|
||||||
}
|
}
|
||||||
return 0.0d;
|
return 0.0d;
|
||||||
|
@@ -1,7 +1,5 @@
|
|||||||
package com.example.fitbot.util.server;
|
package com.example.fitbot.util.server;
|
||||||
|
|
||||||
import java.net.Socket;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for handling WebSocket events.
|
* Interface for handling WebSocket events.
|
||||||
*/
|
*/
|
||||||
|
@@ -10,16 +10,13 @@ import java.io.OutputStream;
|
|||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
public class WebServer implements Runnable {
|
public class WebServer implements Runnable {
|
||||||
|
|
||||||
private ServerSocket serverSocket;
|
private ServerSocket serverSocket;
|
||||||
protected IWebServerHandler eventHandler = (input) -> {}; // No-op.
|
protected IWebServerHandler eventHandler = (input) -> {
|
||||||
|
}; // No-op.
|
||||||
|
|
||||||
private Thread thread;
|
private Thread thread;
|
||||||
private final AtomicBoolean forceClose = new AtomicBoolean(false);
|
private final AtomicBoolean forceClose = new AtomicBoolean(false);
|
||||||
|
@@ -56,7 +56,7 @@
|
|||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent">
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
<com.example.fitbot.ui.components.PersonalMotionPreviewElement
|
<com.example.fitbot.ui.components.ExerciseStatusElement
|
||||||
android:id="@+id/personalMotionPreviewElement"
|
android:id="@+id/personalMotionPreviewElement"
|
||||||
android:layout_width="350dp"
|
android:layout_width="350dp"
|
||||||
android:layout_height="350dp" />
|
android:layout_height="350dp" />
|
||||||
|
Reference in New Issue
Block a user