Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package com.codename1.samples;

import com.codename1.components.ToastBar;
import com.codename1.io.Log;
import com.codename1.media.MediaManager;
import com.codename1.ui.Button;
import com.codename1.ui.Dialog;
import com.codename1.ui.Display;
import com.codename1.ui.Form;
import com.codename1.ui.Label;
import com.codename1.ui.layouts.BoxLayout;

/**
* Test-local copy of the AsyncResource sample used by {@link AsyncResourceSampleTest}.
*/
public class AsyncResourceSample {
private static final String SUCCESS_URI = "https://sample-videos.com/audio/mp3/crowd-cheering.mp3";
private static final String ERROR_URI = "https://sample-videos.com/audio/mp3/crowd-cheering-not-found.mp3";

private Form current;

public void start() {
if (current != null) {
current.show();
return;
}
final Form hi = new Form("Hi World", BoxLayout.y());
hi.add(new Label("Hi World"));
final Button playAsync = new Button("Play Async");
playAsync.addActionListener(e -> handleAsyncMedia(playAsync, SUCCESS_URI));
hi.add(playAsync);

final Button playAsyncErr = new Button("Play Async (Not Found)");
playAsyncErr.addActionListener(e -> handleAsyncMedia(playAsyncErr, ERROR_URI));
hi.add(playAsyncErr);
hi.show();
}

private void handleAsyncMedia(final Button source, String uri) {
source.setEnabled(false);
final ToastBar.Status status = ToastBar.getInstance().createStatus();
status.setMessage("Loading Audio...");
status.setShowProgressIndicator(true);
status.show();
source.repaint();
MediaManager.createMediaAsync(uri, false, null)
.ready(media -> {
status.clear();
source.setEnabled(true);
source.repaint();
media.play();
})
.except(ex -> {
status.clear();
source.setEnabled(true);
source.repaint();
Log.e(ex);
ToastBar.showErrorMessage(ex.getMessage());
});
}

public void stop() {
current = Display.getInstance().getCurrent();
if (current instanceof Dialog) {
((Dialog) current).dispose();
current = Display.getInstance().getCurrent();
}
}

public void destroy() {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
package com.codename1.samples;

import com.codename1.junit.FormTest;
import com.codename1.junit.UITestBase;
import com.codename1.media.Media;
import com.codename1.ui.Button;
import com.codename1.ui.Component;
import com.codename1.ui.Container;
import com.codename1.ui.Display;
import com.codename1.ui.Form;
import com.codename1.util.AsyncResource;

import static org.junit.jupiter.api.Assertions.*;

class AsyncResourceSampleTest extends UITestBase {
private static final String SUCCESS_URI = "https://sample-videos.com/audio/mp3/crowd-cheering.mp3";
private static final String ERROR_URI = "https://sample-videos.com/audio/mp3/crowd-cheering-not-found.mp3";

@FormTest
void playAsyncCompletesAndPlaysMedia() {
AsyncResource<Media> asyncMedia = new AsyncResource<Media>();
FakeMedia media = new FakeMedia();
implementation.setMediaAsync(SUCCESS_URI, asyncMedia);

AsyncResourceSample sample = new AsyncResourceSample();
sample.start();

Button playAsync = findButton(Display.getInstance().getCurrent(), "Play Async");
assertNotNull(playAsync);

playAsync.released();
assertFalse(playAsync.isEnabled());

implementation.completeMediaAsync(SUCCESS_URI, media);
flushSerialCalls();

assertTrue(playAsync.isEnabled());
assertTrue(media.playInvoked);
}

@FormTest
void playAsyncHandlesErrors() {
AsyncResource<Media> asyncMedia = new AsyncResource<Media>();
implementation.setMediaAsync(ERROR_URI, asyncMedia);

AsyncResourceSample sample = new AsyncResourceSample();
sample.start();

Button errorButton = findButton(Display.getInstance().getCurrent(), "Play Async (Not Found)");
assertNotNull(errorButton);

errorButton.released();
assertFalse(errorButton.isEnabled());

RuntimeException failure = new RuntimeException("Resource missing");
implementation.failMediaAsync(ERROR_URI, failure);
flushSerialCalls();

assertTrue(errorButton.isEnabled());
}

private Button findButton(Form form, String text) {
if (form == null) {
return null;
}
return findButtonRecursive(form.getContentPane(), text);
}

private Button findButtonRecursive(Container container, String text) {
for (Component child : container) {
if (child instanceof Button) {
Button button = (Button) child;
if (text.equals(button.getText())) {
return button;
}
}
if (child instanceof Container) {
Button nested = findButtonRecursive((Container) child, text);
if (nested != null) {
return nested;
}
}
}
return null;
}

private static class FakeMedia implements Media {
private boolean playInvoked;

public void play() {
playInvoked = true;
}

public void pause() {
}

public void prepare() {
}

public void cleanup() {
}

public int getTime() {
return 0;
}

public void setTime(int time) {
}

public int getDuration() {
return 0;
}

public int getVolume() {
return 0;
}

public void setVolume(int vol) {
}

public boolean isPlaying() {
return playInvoked;
}

public Component getVideoComponent() {
return null;
}

public boolean isVideo() {
return false;
}

public boolean isFullScreen() {
return false;
}

public void setFullScreen(boolean fullScreen) {
}

public boolean isNativePlayerMode() {
return false;
}

public void setNativePlayerMode(boolean nativePlayerMode) {
}

public void setVariable(String key, Object value) {
}

public Object getVariable(String key) {
return null;
}

public boolean isTimeSupported() {
return true;
}

public boolean isSeekSupported() {
return true;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ public class TestCodenameOneImplementation extends CodenameOneImplementation {
private Media backgroundMedia;
private Media media;
private AsyncResource<Media> mediaAsync;
private final Map<String, AsyncResource<Media>> mediaAsyncByUri = new ConcurrentHashMap<String, AsyncResource<Media>>();
private Purchase inAppPurchase;
private int startRemoteControlInvocations;
private int stopRemoteControlInvocations;
Expand Down Expand Up @@ -339,6 +340,13 @@ public boolean supportsNativeImageCache() {
return nativeImageCacheSupported;
}

private AsyncResource<Media> resolveMediaAsync(String uri) {
if (uri != null && mediaAsyncByUri.containsKey(uri)) {
return mediaAsyncByUri.get(uri);
}
return mediaAsync;
}

@Override
public AsyncResource<Media> createBackgroundMediaAsync(String uri) {
return backgroundMediaAsync;
Expand All @@ -359,7 +367,7 @@ public Media createBackgroundMedia(String uri) throws IOException {

@Override
public AsyncResource<Media> createMediaAsync(String uri, boolean video, Runnable onCompletion) {
return mediaAsync;
return resolveMediaAsync(uri);
}

@Override
Expand All @@ -380,6 +388,34 @@ public void setMediaAsync(AsyncResource<Media> mediaAsync) {
this.mediaAsync = mediaAsync;
}

public void setMediaAsync(String uri, AsyncResource<Media> asyncResource) {
if (uri == null) {
mediaAsync = asyncResource;
} else if (asyncResource == null) {
mediaAsyncByUri.remove(uri);
} else {
mediaAsyncByUri.put(uri, asyncResource);
}
}

public void clearMediaAsyncMappings() {
mediaAsyncByUri.clear();
}

public void completeMediaAsync(String uri, Media value) {
AsyncResource<Media> async = resolveMediaAsync(uri);
if (async != null) {
async.complete(value);
}
}

public void failMediaAsync(String uri, Throwable error) {
AsyncResource<Media> async = resolveMediaAsync(uri);
if (async != null) {
async.error(error);
}
}

@Override
public void initializeTextSelection(TextSelection aThis) {
initializeTextSelectionCount++;
Expand Down