/*
* NativeCanvas.java
*
* Midp Canvas wrapper.
*
* @author Vladimir Kryukov
*/
package jimmui.view.base;
import java.util.*;
import javax.microedition.lcdui.*;
import jimm.*;
import jimm.comm.StringUtils;
import jimm.modules.*;
import jimmui.view.base.touch.TouchState;
import jimmui.view.menu.Select;
/**
*
* @author Vladimir Kryukov
*/
public class NativeCanvas extends Canvas {
private GraphicsEx graphicsEx = new GraphicsEx();
public static final int UIUPDATE_TIME = 250;
private CanvasEx canvas = null;
private Popup popup = null;
private Image bDIimage = null;
// #sijapp cond.if modules_ANDROID is "true" #
private int minScreenMetrics;
// #sijapp cond.end #
// #sijapp cond.if modules_TOUCH is "true"#
private TouchControl touchControl = new TouchControl();
// #sijapp cond.end#
private long firePressTime = 0;
private boolean ignoreKeys = false;
public NativeCanvas() {
// #sijapp cond.if modules_ANDROID is "true" #
minScreenMetrics = Math.min(getWidth(), getHeight());
// #sijapp cond.end #
}
protected void paint(Graphics g) {
if (isDoubleBuffered()) {
paintAllOnGraphics(g);
} else {
try {
if ((null == bDIimage) || (bDIimage.getHeight() != getHeight())) {
bDIimage = Image.createImage(getWidth(), getHeight());
}
paintAllOnGraphics(bDIimage.getGraphics());
g.drawImage(bDIimage, 0, 0, Graphics.TOP | Graphics.LEFT);
} catch (Throwable e) {
paintAllOnGraphics(g);
}
}
}
private void paintAllOnGraphics(Graphics g) {
graphicsEx.setGraphics(g);
try {
CanvasEx c = getCanvas();
if (c instanceof Select) {
c.paintBack(graphicsEx);
}
c.paint(graphicsEx);
} catch(Exception e) {
// #sijapp cond.if modules_DEBUGLOG is "true" #
DebugLog.panic("native", e);
// #sijapp cond.end #
}
graphicsEx.reset();
}
// #sijapp cond.if target="MIDP2" #
protected void showNotify() {
if (Jimm.getJimm().isPaused()) {
Jimm.getJimm().wakeUp();
}
updateMetrix(getWidth(), getHeight());
canvas.restoring();
}
// #sijapp cond.end #
// protected void hideNotify() {
// }
// #sijapp cond.if modules_TOUCH is "true"#
protected void pointerReleased(int x, int y) {
boolean update = canvas.touchPressed;
canvas.touchPressed = false;
Jimm.getJimm().getCL().userActivity();
touchControl.pointerReleased(x, y);
if (update) canvas.invalidate();
}
protected void pointerPressed(int x, int y) {
Jimm.getJimm().getCL().userActivity();
// #sijapp cond.if modules_LIGHT is "true" #
CustomLight.setLightMode(CustomLight.ACTION_KEY_PRESS);
// #sijapp cond.end#
touchControl.pointerPressed(x, y);
}
protected void pointerDragged(int x, int y) {
// #sijapp cond.if modules_LIGHT is "true" #
CustomLight.setLightMode(CustomLight.ACTION_KEY_PRESS);
// #sijapp cond.end#
touchControl.pointerDragged(x, y);
}
// #sijapp cond.end#
// #sijapp cond.if modules_ANDROID is "true"#
public void androidPointerPressed(TouchState state) {
try {
canvas.stylusPressed(state);
if (null != state.region) {
state.region.stylusPressed(canvas, state.fromX, state.fromY);
}
} catch (Exception e) {
jimm.modules.DebugLog.panic("androidPointerPressed", e);
}
}
public void androidPointerTap(TouchState state) {
boolean update = canvas.touchPressed;
canvas.touchPressed = false;
try {
if (null == state.region) {
canvas.stylusTap(state);
} else {
state.region.stylusTap(canvas, state.fromX, state.fromY, state.isLong);
}
} catch (Exception e) {
jimm.modules.DebugLog.panic("androidPointerTap", e);
}
if (update) canvas.invalidate();
}
public void androidPointerMoving(TouchState state, int dx, int dy) {
try {
if (null == state.region) {
if (Math.abs(dy) < Math.abs(dx)) {
canvas.stylusXMoving(state);
} else {
canvas.stylusGeneralYMoved(state);
}
}
} catch (Exception e) {
jimm.modules.DebugLog.panic("androidPointerMoving", e);
}
}
public void androidPointerMoved(TouchState state, int dx, int dy) {
try {
if (null == state.region) {
if (Math.abs(dy) <= Math.abs(dx)) {
canvas.stylusXMoved(state);
} else {
canvas.stylusGeneralYMoved(state);
}
}
} catch (Exception e) {
jimm.modules.DebugLog.panic("androidPointerMoved", e);
}
}
public void androidPointerReleased() {
try {
boolean update = canvas.touchPressed;
canvas.touchPressed = false;
if (update) canvas.invalidate();
} catch (Exception e) {
jimm.modules.DebugLog.panic("androidPointerMoved", e);
}
}
// #sijapp cond.end#
public void setCanvas(CanvasEx canvasEx) {
stopKeyRepeating();
canvas = canvasEx;
// #sijapp cond.if modules_TOUCH is "true"#
touchControl.setCanvas(canvasEx);
// #sijapp cond.end#
// #sijapp cond.if modules_ANDROID isnot "true"#
updateMetrix(getWidth(), getHeight());
// #sijapp cond.end#
}
public CanvasEx getCanvas() {
return canvas;
}
public void setPopup(Popup p) {
popup = p;
repaint();
}
public Popup getPopup() {
return popup;
}
public void stopKeyRepeating() {
ignoreKeys = true;
KeyRepeatTimer.stop();
}
protected void sizeChanged(int w, int h) {
if ((0 == w) || (0 == h)) return;
CanvasEx c = canvas;
try {
if (isShown()) {
updateMetrix(w, h);
c.restoring();
invalidate(c);
}
} catch (Exception ignored) {
}
}
public static final int LEFT_SOFT = 0x00100000;
public static final int RIGHT_SOFT = 0x00100001;
public static final int CLEAR_KEY = 0x00100002;
public static final int CLOSE_KEY = 0x00100003;
public static final int CALL_KEY = 0x00100004;
public static final int CAMERA_KEY = 0x00100005;
public static final int ABC_KEY = 0x00100006;
public static final int VOLPLUS_KEY = 0x00100007;
public static final int VOLMINUS_KEY = 0x00100008;
public static final int NAVIKEY_RIGHT = 0x00100009;
public static final int NAVIKEY_LEFT = 0x0010000A;
public static final int NAVIKEY_UP = 0x0010000B;
public static final int NAVIKEY_DOWN = 0x0010000C;
public static final int NAVIKEY_FIRE = 0x0010000D;
public static final int UNUSED_KEY = 0x0010000F;
public static final int JIMM_BACK = 0x00100010;
public static final int JIMM_MENU = 0x00100011;
public static final int JIMM_SELECT = 0x00100012;
public static final int JIMM_ACTIVATE = 0x00100013;
public int getKey(int code) {
// #sijapp cond.if modules_ANDROID is "true" #
if (Jimm.getJimm().phone.isPhone(PhoneInfo.PHONE_ANDROID)) {
if (-4 == code) {
return CLOSE_KEY;
}
if (-84 == code) {
return CALL_KEY;
}
if (-8 == code) {
return CLOSE_KEY;
}
}
// #sijapp cond.end #
String strCode = null;
try {
strCode = getKeyName(code);
if (null != strCode) {
strCode = strCode.replace('_', ' ').toLowerCase();
}
} catch (IllegalArgumentException ignored) {
}
if (null != strCode) {
if ("soft1".equals(strCode)
|| "soft 1".equals(strCode)
|| "softkey 1".equals(strCode)
|| strCode.startsWith("left soft")) {
return LEFT_SOFT;
}
if ("soft2".equals(strCode)
|| "soft 2".equals(strCode)
|| "softkey 4".equals(strCode)
|| strCode.startsWith("right soft")) {
return RIGHT_SOFT;
}
if ("on/off".equals(strCode) || ("ba" + "ck").equals(strCode)) {
return CLOSE_KEY;
}
if (("clea" + "r").equals(strCode)) {
return CLEAR_KEY;
}
// if ("soft3".equals(strCode)) {
// return MIDDLE_SOFT;
// }
if (("se" + "nd").equals(strCode)) {
return CALL_KEY;
}
if (("sele" + "ct").equals(strCode) || ("o" + "k").equals(strCode)
|| "fire".equals(strCode) || "navi-center".equals(strCode)
|| "enter".equals(strCode)) {
return NAVIKEY_FIRE;
}
if ("start".equals(strCode)) {
return CALL_KEY;
}
if ("up".equals(strCode) || "navi-up".equals(strCode)
|| "up arrow".equals(strCode)) {
return NAVIKEY_UP;
}
if ("down".equals(strCode) || "navi-down".equals(strCode)
|| "down arrow".equals(strCode)) {
return NAVIKEY_DOWN;
}
if ("left".equals(strCode) || "navi-left".equals(strCode)
|| "left arrow".equals(strCode) || "sideup".equals(strCode)) {
return NAVIKEY_LEFT;
}
if ("right".equals(strCode) || "navi-right".equals(strCode)
|| "right arrow".equals(strCode) || "sidedown".equals(strCode)) {
return NAVIKEY_RIGHT;
}
}
if(code == -6 || code == -21 || code == 21 || code == 105
|| code == -202 || code == 113 || code == 57345
|| code == 0xFFBD) {
return LEFT_SOFT;
}
if (!Jimm.getJimm().phone.isPhone(PhoneInfo.PHONE_SE)) {
if (-22 == code) {
return RIGHT_SOFT;
}
}
if (code == -7 || code == 22 || code == 106
|| code == -203 || code == 112 || code == 57346
|| code == 0xFFBB) {
return RIGHT_SOFT;
}
if (-41 == code) { // Alcatel-OT-800/1.0
return NAVIKEY_FIRE;
}
if (-5 == code) {
return NAVIKEY_FIRE;
}
if (63557 == code) { // nokia e63
return NAVIKEY_FIRE;
}
if (code == -8) {
return CLEAR_KEY;
}
if ((-11 == code) || (-12 == code)) {
return CLOSE_KEY;
}
if ((-26 == code) || (-24 == code)) {
return CAMERA_KEY;
}
if (code == -10) {
return CALL_KEY;
}
if (code == -50 || code == 1048582) {
return ABC_KEY;
}
if (code == -36) {
return VOLPLUS_KEY;
}
if (code == -37) {
return VOLMINUS_KEY;
}
return code;
}
protected void keyPressed(int keyCode) {
ignoreKeys = false;
// #sijapp cond.if modules_LIGHT is "true" #
CustomLight.setLightMode(CustomLight.ACTION_KEY_PRESS);
// #sijapp cond.end#
doKeyReaction(keyCode, CanvasEx.KEY_PRESSED);
}
protected void keyRepeated(int keyCode) {
// #sijapp cond.if modules_LIGHT is "true" #
CustomLight.setLightMode(CustomLight.ACTION_KEY_PRESS);
// #sijapp cond.end#
// #sijapp cond.if modules_ANDROID is "true" #
doKeyReaction(keyCode, CanvasEx.KEY_REPEATED);
// #sijapp cond.end #
}
protected void keyReleased(int keyCode) {
doKeyReaction(keyCode, CanvasEx.KEY_RELEASED);
}
public int getAction(int key, int keyCode) {
if (key != keyCode) {
return key;
}
switch (keyCode) {
case KEY_NUM2: return NAVIKEY_UP;
case KEY_NUM3: return 0;
case KEY_NUM4: return NAVIKEY_LEFT;
case KEY_NUM5: return NAVIKEY_FIRE;
case KEY_NUM6: return NAVIKEY_RIGHT;
case KEY_NUM7: return 0;
case KEY_NUM8: return NAVIKEY_DOWN;
case KEY_NUM9: return 0;
case KEY_POUND: return 0;
case KEY_STAR: return 0;
}
try {// getGameAction can raise exception
int action = getGameAction(keyCode);
switch (action) {
case Canvas.RIGHT: return NAVIKEY_RIGHT;
case Canvas.LEFT: return NAVIKEY_LEFT;
case Canvas.UP: return NAVIKEY_UP;
case Canvas.DOWN: return NAVIKEY_DOWN;
case Canvas.FIRE: return NAVIKEY_FIRE;
}
} catch (Exception ignored) {
}
return key;
}
private int qwerty2phone(int key) {
switch (key) {
// lat
case 'm': return KEY_NUM0;
case 'r': return KEY_NUM1;
case 't': return KEY_NUM2;
case 'z': return KEY_NUM3;
case 'f': return KEY_NUM4;
case 'g': return KEY_NUM5;
case 'h': return KEY_NUM6;
case 'v': return KEY_NUM7;
case 'b': return KEY_NUM8;
case 'n': return KEY_NUM9;
case 'j': return KEY_POUND;
case 'u': return KEY_STAR;
// rus
case 1100: return KEY_NUM0;
case 1082: return KEY_NUM1;
case 1077: return KEY_NUM2;
case 1103: return KEY_NUM3;
case 1072: return KEY_NUM4;
case 1087: return KEY_NUM5;
case 1088: return KEY_NUM6;
case 1084: return KEY_NUM7;
case 1080: return KEY_NUM8;
case 1090: return KEY_NUM9;
case 1086: return KEY_POUND;
case 1075: return KEY_STAR;
}
return key;
}
private int qwerty2action(int key, int keyCode) {
switch (key) {
case KEY_NUM0: return 0;
case KEY_NUM1: return 0;
case KEY_NUM2: return NAVIKEY_UP;
case KEY_NUM3: return 0;
case KEY_NUM4: return NAVIKEY_LEFT;
case KEY_NUM5: return NAVIKEY_FIRE;
case KEY_NUM6: return NAVIKEY_RIGHT;
case KEY_NUM7: return 0;
case KEY_NUM8: return NAVIKEY_DOWN;
case KEY_NUM9: return 0;
case KEY_POUND: return 0;
case KEY_STAR: return 0;
}
return getAction(key, keyCode);
}
static boolean isOldSeLike() {
return (2 == Options.getInt(Options.OPTION_KEYBOARD));
}
private void doKeyReaction(int keyCode, int type) {
doKeyReaction(canvas, keyCode, type);
}
private void doKeyReaction(CanvasEx c, int keyCode, int type) {
if (ignoreKeys) {
return;
}
int key = getKey(keyCode);
int action;
if (1 == Options.getInt(Options.OPTION_KEYBOARD)) {
boolean executed = c.qwertyKey(keyCode, type);
if (executed) {
return;
}
int qwertyKeyCode = qwerty2phone(keyCode);
if (qwertyKeyCode != keyCode) {
key = qwertyKeyCode;
}
action = qwerty2action(key, keyCode);
} else {
if (isOldSeLike() && (null != c.getSoftBar())) {
MySoftBar softBar = c.getSoftBar();
switch (key) {
case LEFT_SOFT:
key = softBar.isSwapped() ? RIGHT_SOFT : NAVIKEY_FIRE;
if (softBar.isNotSwappable()) {
key = LEFT_SOFT;
}
break;
case RIGHT_SOFT:
if (softBar.hasRightSoft()) {
key = softBar.isNotSwappable() ? RIGHT_SOFT : LEFT_SOFT;
} else {
key = UNUSED_KEY;
}
break;
case CLOSE_KEY:
key = RIGHT_SOFT;
break;
}
}
action = getAction(key, keyCode);
}
Jimm.getJimm().getCL().userActivity();
doKeyReaction(c, key, action, type);
// #sijapp cond.if modules_ANDROID isnot "true" #
if (CanvasEx.KEY_PRESSED == type) { // navigation keys only
switch (action) {
case NAVIKEY_RIGHT:
case NAVIKEY_LEFT:
case NAVIKEY_UP:
case NAVIKEY_DOWN:
case NAVIKEY_FIRE:
case KEY_NUM1:
case KEY_NUM3:
case KEY_NUM7:
case KEY_NUM9:
KeyRepeatTimer.start(this, key, action, c);
break;
}
} else {
KeyRepeatTimer.stop();
}
// #sijapp cond.end #
}
private int mapToJimmAction(CanvasEx c, int keyCode) {
if ((NativeCanvas.RIGHT_SOFT == keyCode) || (NativeCanvas.CLOSE_KEY == keyCode)) {
return NativeCanvas.JIMM_BACK;
}
if (NativeCanvas.LEFT_SOFT == keyCode) {
return c.hasMenu() ? NativeCanvas.JIMM_MENU : NativeCanvas.JIMM_SELECT;
}
return 0;
}
private void doKeyReaction(final CanvasEx c, final int keyCode, final int action, int type) {
try {
if (ignoreKeys) {
return;
}
int jimmAction = mapToJimmAction(c, keyCode);
if (0 < jimmAction) {
if ((NativeCanvas.CLOSE_KEY == keyCode)
&& Jimm.getJimm().phone.isPhone(PhoneInfo.PHONE_NOKIA_S60)
&& hasPointerEvents()) {
return;
}
if (CanvasEx.KEY_PRESSED == type) {
c.execJimmAction(jimmAction);
}
return;
}
if (NativeCanvas.NAVIKEY_FIRE == action) {
if (CanvasEx.KEY_PRESSED == type) {
firePressTime = System.currentTimeMillis();
}
if ('5' == keyCode) {
if (CanvasEx.KEY_PRESSED == type) {
TimerTask task = new TimerTask() {
public void run() {
firePressTime = 0;
c.doKeyReaction(keyCode, action, CanvasEx.KEY_RELEASED);
}
};
longFilePressTask = task;
Timer t = new Timer();
t.schedule(task, Display.LONG_INTERVAL);
}
if (isLongFirePress()) {
return;
}
if (CanvasEx.KEY_RELEASED == type) {
TimerTask task = longFilePressTask;
longFilePressTask = null;
if (null != task) {
task.cancel();
}
}
}
}
c.doKeyReaction(keyCode, action, type);
} catch (Exception e) {
// #sijapp cond.if modules_DEBUGLOG is "true" #
DebugLog.panic("Key error", e);
// #sijapp cond.end #
}
}
private TimerTask longFilePressTask = null;
void emulateKey(CanvasEx c, int key) {
if (null == c) c = canvas;
ignoreKeys = false;
doKeyReaction(c, key, CanvasEx.KEY_PRESSED);
doKeyReaction(c, key, CanvasEx.KEY_RELEASED);
}
public void invalidate(CanvasEx canvasEx) {
if (canvas == canvasEx) {
repaint();
}
}
private void updateMetrix(int w, int h) {
if ((0 == w) || (0 == h)) return;
CanvasEx c = canvas;
int prevW = c.getWidth();
int prevH = c.getHeight();
// #sijapp cond.if modules_ANDROID is "true" #
minScreenMetrics = Math.max(minScreenMetrics, Math.min(w, h));
// #sijapp cond.end #
c.setSize(w, h);
c.sizeChanged(prevW, prevH, c.getWidth(), c.getHeight());
}
// #sijapp cond.if modules_ANDROID is "true" #
public void updateSize() {
CanvasEx c = canvas;
c.setSize(getWidth(), getHeight());
}
// #sijapp cond.end #
public int getMinScreenMetrics() {
// #sijapp cond.if modules_ANDROID is "true" #
String supports = System.getProperty("device.accelerometer");
if (StringUtils.isEmpty(supports)) {
return getWidth();
}
if (true) return minScreenMetrics;
// #sijapp cond.end #
// #sijapp cond.if modules_TOUCH is "true" #
if (true) return Math.min(getWidth(), getHeight());
// #sijapp cond.end #
return getWidth();
}
public boolean isLongFirePress() {
return Display.isLongAction(firePressTime);
}
private static class KeyRepeatTimer extends TimerTask {
private static Timer timer = new Timer();
private int key;
private int action;
private CanvasEx canvas;
private NativeCanvas nativeCanvas;
private int slowlyIterations = 8;
public static void start(NativeCanvas nativeCanvas, int key, int action, CanvasEx c) {
try {
stop();
timer = new Timer();
KeyRepeatTimer repeater = new KeyRepeatTimer(nativeCanvas, key, action, c);
timer.schedule(repeater, 300, 80);
} catch (Exception ignored) {
ignored.printStackTrace();
}
}
public static void stop() {
Timer t = timer;
if (null != t) {
t.cancel();
t = null;
}
}
private KeyRepeatTimer(NativeCanvas nativeCanvas, int keyCode, int actionCode, CanvasEx c) {
key = keyCode;
action = actionCode;
canvas = c;
this.nativeCanvas = nativeCanvas;
}
public void run() {
if (0 < slowlyIterations) {
slowlyIterations--;
if (0 != slowlyIterations % 2) {
return;
}
}
if (!Jimm.getJimm().getDisplay().isShown(nativeCanvas)
|| nativeCanvas.canvas != canvas) {
KeyRepeatTimer.stop();
return;
}
nativeCanvas.doKeyReaction(canvas, key, action, CanvasEx.KEY_REPEATED);
}
}
}