/**
* MicroEmulator
* Copyright (C) 2001-2007 Bartek Teodorczyk <barteo@barteo.net>
* Copyright (C) 2007 Rushabh Doshi <radoshi@cs.stanford.edu> Pelago, Inc
*
* It is licensed under the following two licenses as alternatives:
* 1. GNU Lesser General Public License (the "LGPL") version 2.1 or any newer version
* 2. Apache License (the "AL") Version 2.0
*
* You may not use this file except in compliance with at least one of
* the above two licenses.
*
* You may obtain a copy of the LGPL at
* http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt
*
* You may obtain a copy of the AL at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the LGPL or the AL for the specific language governing permissions and
* limitations.
*
* Contributor(s):
* 3GLab
* Andres Navarro
*
* @version $Id: Display.java 2496 2011-05-07 11:27:52Z barteo@gmail.com $
*/
package javax.microedition.lcdui;
import java.util.Timer;
import java.util.TimerTask;
import javax.microedition.midlet.MIDlet;
import jimmui.view.base.NativeCanvas;
import jimmui.view.chat.Chat;
import org.microemu.android.device.AndroidDeviceDisplay;
import org.microemu.android.device.ui.AndroidCanvasUI;
import org.microemu.android.device.ui.CanvasView;
import ru.net.jimm.JimmActivity;
import org.microemu.DisplayAccess;
import org.microemu.MIDletBridge;
import org.microemu.device.DeviceFactory;
import org.microemu.device.ui.DisplayableUI;
import org.microemu.device.ui.EventDispatcher;
import org.microemu.device.ui.ItemUI;
public class Display {
public static final int LIST_ELEMENT = 1;
public static final int CHOICE_GROUP_ELEMENT = 2;
public static final int ALERT = 3;
public static final int COLOR_BACKGROUND = 0;
public static final int COLOR_FOREGROUND = 1;
public static final int COLOR_HIGHLIGHTED_BACKGROUND = 2;
public static final int COLOR_HIGHLIGHTED_FOREGROUND = 3;
public static final int COLOR_BORDER = 4;
public static final int COLOR_HIGHLIGHTED_BORDER = 5;
private Displayable current = null;
private DisplayAccessor accessor = null;
private EventDispatcher eventDispatcher;
/**
* Wrap a key event as a runnable so it can be thrown into the event
* processing queue. Note that this may be a bit buggy, since events are
* supposed to propogate to the head of the queue and not get tied behind
* other repaints or serial calls in the queue.
*
* @author radoshi
*
*/
private final class KeyEvent extends EventDispatcher.Event {
static final short KEY_PRESSED = 0;
static final short KEY_RELEASED = 1;
static final short KEY_REPEATED = 2;
private short type;
private int keyCode;
KeyEvent(short type, int keyCode) {
eventDispatcher.super();
this.type = type;
this.keyCode = keyCode;
}
public void run() {
switch (type) {
case KEY_PRESSED:
if (current != null) {
current.keyPressed(keyCode);
}
break;
case KEY_RELEASED:
if (current != null) {
current.keyReleased(keyCode);
}
break;
case KEY_REPEATED:
if (current != null) {
current.keyRepeated(keyCode);
}
break;
}
}
}
private final class HideNotifyEvent extends EventDispatcher.RunnableEvent {
public HideNotifyEvent(EventDispatcher eventDispatcher, Runnable runnable) {
eventDispatcher.super(runnable);
}
}
private final class ShowNotifyEvent extends EventDispatcher.RunnableEvent {
public ShowNotifyEvent(EventDispatcher eventDispatcher, Runnable runnable) {
eventDispatcher.super(runnable);
}
}
private class DisplayAccessor implements DisplayAccess {
Display display;
DisplayAccessor(Display d) {
display = d;
}
public void commandAction(final Command c, final Displayable d) {
if (c.isRegularCommand()) {
if (d == null) {
return;
}
final CommandListener listener = d.getCommandListener();
if (listener == null) {
return;
}
eventDispatcher.put(new Runnable() {
public void run() {
listener.commandAction(c, d);
}
});
} else {
// item contained command
commandAction(c.getOriginalCommand(), c.getFocusedItem());
}
}
public void commandAction(final Command c, final Item item) {
final ItemCommandListener listener = item.getItemCommandListener();
if (listener == null) {
return;
}
eventDispatcher.put(new Runnable() {
public void run() {
listener.commandAction(c, item);
}
});
}
public Display getDisplay() {
return display;
}
// TODO according to the specification this should be
// only between show and hide notify...
// check later
// Andres Navarro
public void keyPressed(int keyCode) {
eventDispatcher.put(new KeyEvent(KeyEvent.KEY_PRESSED, keyCode));
}
public void keyRepeated(int keyCode) {
eventDispatcher.put(new KeyEvent(KeyEvent.KEY_REPEATED, keyCode));
}
public void keyReleased(int keyCode) {
eventDispatcher.put(new KeyEvent(KeyEvent.KEY_RELEASED, keyCode));
}
public void pointerPressed(final int x, final int y) {
if (current != null) {
eventDispatcher.put(eventDispatcher.new PointerEvent(new Runnable() {
public void run() {
current.pointerPressed(x, y);
}
}, EventDispatcher.PointerEvent.POINTER_PRESSED, x, y));
}
}
public void pointerReleased(final int x, final int y) {
if (current != null) {
eventDispatcher.put(eventDispatcher.new PointerEvent(new Runnable() {
public void run() {
current.pointerReleased(x, y);
}
}, EventDispatcher.PointerEvent.POINTER_RELEASED, x, y));
}
}
public void pointerDragged(final int x, final int y) {
if (current != null) {
eventDispatcher.put(eventDispatcher.new PointerEvent(new Runnable() {
public void run() {
current.pointerDragged(x, y);
}
}, EventDispatcher.PointerEvent.POINTER_DRAGGED, x, y));
}
}
public void paint(Graphics g) {
// TODO consider removal of DisplayAccess::paint(..)
if (current != null) {
try {
g.setCanvasSize(current.getWidth(), current.getHeight());
current.paint(g);
} catch (Throwable th) {
th.printStackTrace();
}
g.translate(-g.getTranslateX(), -g.getTranslateY());
}
}
public Displayable getCurrent() {
return getDisplay().getCurrent();
}
public DisplayableUI getDisplayableUI(Displayable displayable) {
if (displayable == null) {
return null;
}
return displayable.getUi();
}
public ItemUI getItemUI(Item item) {
return item.ui;
}
public boolean isFullScreenMode() {
Displayable current = getCurrent();
if (current instanceof Canvas) {
return ((Canvas) current).fullScreenMode;
} else {
return false;
}
}
public void hideNotify() {
Displayable current = getCurrent();
if (current != null) {
current.hideNotify();
}
}
public void setCurrent(Displayable d) {
getDisplay().setCurrent(d);
}
public void sizeChanged() {
if (current != null) {
current.sizeChanged(Display.this);
}
}
public void repaint() {
Displayable d = getCurrent();
if (d != null) {
getDisplay().repaint(d, 0, 0, d.getWidth(), d.getHeight());
}
}
public void clean() {
if (current != null) {
eventDispatcher.put(new HideNotifyEvent(eventDispatcher, new Runnable() {
private Displayable displayable = current;
public void run() {
displayable.hideNotify(Display.this);
}
}));
}
eventDispatcher.cancel();
timer.cancel();
}
}
private final Timer timer = new Timer();
/**
* Wrap any runnable as a timertask so that when the timer gets fired, the
* runnable gets run
*
* @author radoshi
*
*/
private final class RunnableWrapper extends TimerTask {
private final Runnable runnable;
RunnableWrapper(Runnable runnable) {
this.runnable = runnable;
}
public void run() {
eventDispatcher.put(runnable);
}
}
Display() {
accessor = new DisplayAccessor(this);
eventDispatcher = DeviceFactory.getDevice().getUIFactory().createEventDispatcher(this);
// timer.scheduleAtFixedRate(new RunnableWrapper(new TickerPaintTask()), 0, Ticker.PAINT_TIMEOUT);
}
public void callSerially(Runnable runnable) {
eventDispatcher.put(runnable);
}
public int numAlphaLevels() {
return DeviceFactory.getDevice().getDeviceDisplay().numAlphaLevels();
}
public int numColors() {
return DeviceFactory.getDevice().getDeviceDisplay().numColors();
}
public boolean flashBacklight(int duration) {
return DeviceFactory.getDevice().getDeviceDisplay().flashBacklight(duration);
}
public static Display getDisplay(MIDlet m) {
Display result;
if (MIDletBridge.getMIDletAccess().getDisplayAccess() == null) {
result = new Display();
MIDletBridge.getMIDletAccess().setDisplayAccess(result.accessor);
} else {
result = MIDletBridge.getMIDletAccess().getDisplayAccess().getDisplay();
}
return result;
}
public int getColor(int colorSpecifier) {
// TODO implement better
switch (colorSpecifier) {
case COLOR_BACKGROUND:
case COLOR_HIGHLIGHTED_FOREGROUND:
case COLOR_HIGHLIGHTED_BORDER:
return 0xFFFFFF;
default:
return 0x000000;
}
}
public int getBorderStyle(boolean highlighted) {
// TODO implement better
return highlighted ? Graphics.DOTTED : Graphics.SOLID;
}
public int getBestImageWidth(int imageType) {
// TODO implement
return 0;
}
public int getBestImageHeight(int imageType) {
// TODO implement
return 0;
}
public Displayable getCurrent() {
return current;
}
public boolean isColor() {
return DeviceFactory.getDevice().getDeviceDisplay().isColor();
}
private void updateChatLine(Displayable displayable) {
if (displayable instanceof NativeCanvas) {
NativeCanvas c = (NativeCanvas) displayable;
DisplayableUI ui = ((Canvas)c).getUi();
if (c.getCanvas() instanceof Chat) {
((AndroidCanvasUI) ui).setInputVisibility(true, (Chat)c.getCanvas());
} else {
((AndroidCanvasUI) ui).setInputVisibility(false, null);
}
c.updateSize();
}
}
public void setCurrent(final Displayable nextDisplayable) {
final Displayable prevDisplayable = current;
if (nextDisplayable == prevDisplayable) {
updateChatLine(nextDisplayable);
nextDisplayable.repaint();
return;
}
if (nextDisplayable != null) {
eventDispatcher.put(new ShowNotifyEvent(eventDispatcher, new Runnable() {
public void run() {
if (prevDisplayable != null) {
eventDispatcher.put(new HideNotifyEvent(eventDispatcher, new Runnable() {
public void run() {
prevDisplayable.hideNotify(Display.this);
}
}));
}
updateChatLine(nextDisplayable);
nextDisplayable.showNotify(Display.this);
Display.this.current = nextDisplayable;
nextDisplayable.repaint();
}
}));
} else {
ru.net.jimm.JimmActivity.getInstance().minimizeApp();
}
}
public void setCurrentItem(Item item) {
if (item.owner != current) {
setCurrent(item.owner);
}
}
public boolean vibrate(int duration) {
return DeviceFactory.getDevice().vibrate(duration);
}
static int getGameAction(int keyCode) {
return DeviceFactory.getDevice().getInputMethod().getGameAction(keyCode);
}
static int getKeyCode(int gameAction) {
return DeviceFactory.getDevice().getInputMethod().getKeyCode(gameAction);
}
static String getKeyName(int keyCode) throws IllegalArgumentException {
return DeviceFactory.getDevice().getInputMethod().getKeyName(keyCode);
}
boolean isShown(Displayable d) {
if (current == null || current != d) {
return false;
} else {
return JimmActivity.getInstance().isVisible();
}
}
void repaint(Displayable d, int x, int y, int width, int height) {
if ((current == d) && d.isShown()) {
eventDispatcher.put(eventDispatcher.new PaintEvent(x, y, width, height));
}
}
void serviceRepaints() {
//
// If service repaints is being called from the event thread, then we
// just execute an immediate repaint and call it a day. If it is being
// called from another thread, then we setup a repaint barrier and wait
// for that barrier to execute
//
if (EventDispatcher.EVENT_DISPATCHER_NAME.equals(Thread.currentThread().getName())) {
if (current != null) {
DeviceFactory.getDevice().getDeviceDisplay().repaint(0, 0, current.getWidth(), current.getHeight());
}
return;
}
eventDispatcher.serviceRepaints();
}
}