/*
Реализация спецификаций CLDC версии 1.1 (JSR-139), MIDP версии 2.1 (JSR-118)
и других спецификаций для функционирования компактных приложений на языке
Java (мидлетов) в среде программного обеспечения Малик Эмулятор.
Copyright © 2016–2017, 2019–2023 Малик Разработчик
Это свободная программа: вы можете перераспространять ее и/или изменять
ее на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Эта программа распространяется в надежде, что она будет полезной,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
общественной лицензии GNU.
Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<https://www.gnu.org/licenses/>.
*/
package malik.emulator.microedition;
import java.io.*;
import javax.microedition.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.media.*;
import javax.microedition.media.protocol.*;
import malik.emulator.application.*;
import malik.emulator.fileformats.graphics.*;
import malik.emulator.media.graphics.*;
import malik.emulator.media.sound.*;
import malik.emulator.microedition.media.*;
public abstract class DeviceManager extends AppProxy
{
public static final int READ = 1;
public static final int WRITE = 2;
public static final int READ_WRITE = 3;
public static final String TONE_DEVICE_LOCATOR = "device://tone";
public static final String MIDI_DEVICE_LOCATOR = "device://midi";
private static DeviceManager INSTANCE;
public static DeviceManager getInstance() {
return INSTANCE;
}
private boolean paused;
private Display current;
private final Display main;
private final DeviceSettings settings;
private final DeviceControl vibrator;
private final DeviceControl backlight;
private final TimeBase systemTimeBase;
private SyntheticSoundPlayer tonePlayer;
protected DeviceManager() {
SystemDisplay display;
DeviceSettings settings;
DeviceControl empty;
DeviceControl vibrator;
DeviceControl backlight;
TimeBase systemTimeBase;
if(INSTANCE != null)
{
throw new InstantiationError("DeviceManager: нельзя создать ещё один экземпляр DeviceManager. Используйте выражение DeviceManager.getInstance().");
}
INSTANCE = this;
empty = new EmptyDeviceControl();
if((settings = createSettings()) == null) settings = new DeviceSettings();
this.settings = settings;
settings.loadMIDletDescriptor();
settings.loadMIDletProperties();
if((display = createMainDisplay()) == null)
{
RasterCanvas screen = RasterCanvas.screen;
display = new SystemDisplay(false, screen.getWidth(), screen.getHeight());
}
this.main = display;
this.current = display;
if((vibrator = createVibrator()) == null) vibrator = empty;
this.vibrator = vibrator;
if((backlight = createBacklight()) == null) backlight = empty;
this.backlight = backlight;
if((systemTimeBase = createSystemTimeBase()) == null) systemTimeBase = new SystemTimeBase();
this.systemTimeBase = systemTimeBase;
}
public abstract String[] getSupportedContentTypes(String protocol);
public abstract String[] getSupportedProtocols(String contentType);
public abstract Player createPlayer(String locator) throws IOException, MediaException;
public abstract Player createPlayer(DataSource source) throws IOException, MediaException;
public abstract Player createPlayer(InputStream stream, String contentType) throws IOException, MediaException;
public abstract Connection openConnection(String url, int mode, boolean timeouts) throws IOException;
public abstract ImageDecoder openImageDecoder(InputStream stream) throws IOException;
public void playTone(int note, int duration, int volume) throws MediaException {
int noteOnMessage;
final int noteOffMessage;
final SyntheticSoundPlayer tonePlayer;
if(note < 0x00 || note > 0x7f)
{
throw new IllegalArgumentException("Manager.playTone: аргумент note выходит из диапазона.");
}
if(duration <= 0)
{
throw new IllegalArgumentException("Manager.playTone: аргумент duration может быть только положительным.");
}
if(volume < 0) volume = 0;
if(volume > 100) volume = 100;
volume = volume * SoundPlayer.MAX_VOLUME / 100;
noteOnMessage = (noteOffMessage = 0x900000 | note << 8) | volume;
try
{
SyntheticSoundPlayer player;
if((player = this.tonePlayer) == null) player = this.tonePlayer = SyntheticSoundPlayer.open();
(tonePlayer = player).sendMessage(noteOnMessage);
}
catch(SoundPlayerException e)
{
throw new MediaException(e.getRealMessage());
}
Scheduler.schedule(new Scheduler.Task() {
public void run() {
try
{
tonePlayer.sendMessage(noteOffMessage);
}
catch(SoundPlayerException e)
{
e.printRealStackTrace();
}
}
}, (long) duration, Scheduler.MONOPOLY);
}
public void applicationStarted(Display display) {
setCurrentDisplay(display);
}
public void applicationStopped(Display display) {
setCurrentDisplay(main);
}
public void setCurrentDisplay(Display current) {
if(current != null)
{
((VisibleElement) writeCurrentDisplay(current)).hide();
((VisibleElement) current).show();
}
}
public boolean isVisibleDisplay(Display display) {
return current == display;
}
public final boolean isPaused() {
return paused;
}
public final Display getCurrentDisplay() {
return current;
}
public final Display getMainDisplay() {
return main;
}
public final DeviceSettings getSettings() {
return settings;
}
public final DeviceControl getVibrator() {
return vibrator;
}
public final DeviceControl getBacklight() {
return backlight;
}
public final TimeBase getSystemTimeBase() {
return systemTimeBase;
}
protected abstract void showStartScreen(Display display);
protected abstract void showConsoleScreen(Display display);
protected abstract void showExitAppScreen(Display display);
protected void appLaunch() {
Display display;
setCurrentDisplay(display = main);
showStartScreen(display);
}
protected void keyboardEvent(KeyboardEvent event) {
Display current;
if((current = this.current) instanceof MIDletDisplay)
{
boolean console;
int key = event.getKey();
Display main = this.main;
DeviceSettings settings = this.settings;
switch(event.getAction())
{
case KeyboardEvent.ACTION_KEY_PRESSED:
case KeyboardEvent.ACTION_KEY_REPEATED:
if(key == settings.getKeyUsedAs(DeviceSettings.DEVICE_KEY_CONSOLE) || key == settings.getKeyUsedAs(DeviceSettings.DEVICE_KEY_EXITAPP)) return;
break;
case KeyboardEvent.ACTION_KEY_RELEASED:
if((console = key == settings.getKeyUsedAs(DeviceSettings.DEVICE_KEY_CONSOLE)) || key == settings.getKeyUsedAs(DeviceSettings.DEVICE_KEY_EXITAPP))
{
if(console)
{
showConsoleScreen(main);
} else
{
showExitAppScreen(main);
}
setCurrentDisplay(main);
return;
}
break;
}
}
current.handleKeyboardEvent(event);
}
protected void pointerEvent(PointerEvent event) {
Display current = this.current;
event.translateTo(current.getLeft(), current.getTop());
current.handlePointerEvent(event);
}
protected void windowShow() {
paused = false;
((VisibleElement) current).show();
}
protected void windowHide() {
paused = true;
((VisibleElement) current).hide();
}
protected SystemDisplay createMainDisplay() {
return null;
}
protected DeviceSettings createSettings() {
return null;
}
protected DeviceControl createVibrator() {
return null;
}
protected DeviceControl createBacklight() {
return null;
}
protected TimeBase createSystemTimeBase() {
return null;
}
protected final Display writeCurrentDisplay(Display current) {
if(current == null)
{
throw new NullPointerException("DeviceManager.writeCurrent: аргумент current равен нулевой ссылке.");
}
Display previous = this.current;
this.current = current;
return previous;
}
}
final class EmptyDeviceControl extends Object implements DeviceControl
{
public EmptyDeviceControl() {
}
public void start(long durationInMillis) {
}
public void start() {
}
public void stop() {
}
}