Series 40 full touch and Nokia Asha software platform
devices add support for multi-point touch. On these phones, you should
set a boolean to disable pointerPressed()
and instead
use pointersPressed()
. Disabling the alternate logic
path will help prevent odd multi-platform side effects from responding
to both the single touch and multitouch logic.
All Nokia Series
40 touch phones and Nokia Asha software platform devices support the Gesture API. There are, however, differences in gesture support among newer
phones with multiple touch devices supporting additional pinch gestures.
If you are also supporting non-touch devices, they do not support
gestures. To work past these differences, make gesture support a selective
enhancement isolated to a delegate class by itself and giving the
relevant information back to the Canvas
for device-neutral
handling.
In the code below, notice that the GESTURE_ALL constant has different values on different phones. This example is intended for compilation with Nokia SDK 2.0 or later.
public final class GestureHandler implements FrameAnimatorListener, GestureListener { public static final int FRAME_ANIMATOR_VERTICAL = FrameAnimator.FRAME_ANIMATOR_VERTICAL; public static final int FRAME_ANIMATOR_HORIZONTAL = FrameAnimator.FRAME_ANIMATOR_HORIZONTAL; public static final int FRAME_ANIMATOR_FREE_ANGLE = FrameAnimator.FRAME_ANIMATOR_FREE_ANGLE; public static final int FRAME_ANIMATOR_FRICTION_LOW = FrameAnimator.FRAME_ANIMATOR_FRICTION_LOW; public static final int FRAME_ANIMATOR_FRICTION_MEDIUM = FrameAnimator.FRAME_ANIMATOR_FRICTION_MEDIUM; public static final int FRAME_ANIMATOR_FRICTION_HIGH = FrameAnimator.FRAME_ANIMATOR_FRICTION_HIGH; private GestureCanvas canvas; private final FrameAnimator animator = new FrameAnimator(); private GestureInteractiveZone giz; public GestureHandler() { try { giz = new GestureInteractiveZone(GestureInteractiveZone.GESTURE_ALL); } catch (Throwable t) { //#debug Log.e(L.class.getName(), "Cannot register GESTURE_ALL, backwards compatibility fallback", e); giz = new GestureInteractiveZone(63); // GESTURE_ALL had a different value in SDK 1.1 and 1.0 } } public void setCanvas(final GestureCanvas canvas) { this.canvas = canvas; } public void gestureAction(final Object container, final GestureInteractiveZone gestureInteractiveZone, final GestureEvent ge) { switch (ge.getType()) { // Pinch to force reload case GestureInteractiveZone.GESTURE_PINCH: canvas.gesturePinch( ge.getPinchDistanceStarting(), ge.getPinchDistanceCurrent(), ge.getPinchDistanceChange(), ge.getPinchCenterX(), ge.getPinchCenterY(), ge.getPinchCenterChangeX(), ge.getPinchCenterChangeY()); break; case GestureInteractiveZone.GESTURE_TAP: canvas.gestureTap(ge.getStartX(), ge.getStartY()); break; case GestureInteractiveZone.GESTURE_LONG_PRESS: canvas.gestureLongPress(ge.getStartX(), ge.getStartY()); break; case GestureInteractiveZone.GESTURE_LONG_PRESS_REPEATED: canvas.gestureLongPressRepeated(ge.getStartX(), ge.getStartY()); break; case GestureInteractiveZone.GESTURE_DRAG: canvas.gestureDrag(ge.getStartX(), canvas.getScrollY(), ge.getDragDistanceX(), ge.getDragDistanceY()); break; case GestureInteractiveZone.GESTURE_DROP: canvas.gestureDrop(ge.getStartX(), ge.getStartY(), ge.getDragDistanceX(), ge.getDragDistanceY()); break; case GestureInteractiveZone.GESTURE_FLICK: canvas.gestureFlick(ge.getStartX(), canvas.getScrollY(), ge.getFlickDirection(), ge.getFlickSpeed(), ge.getFlickSpeedX(), ge.getFlickSpeedY()); break; default: ; } } public void animate(final FrameAnimator animator, final int x, final int y, final short delta, final short deltaX, final short deltaY, final boolean lastFrame) { canvas.animate(x, y, delta, deltaX, deltaY, lastFrame); } public void animateDrag(final int x, final int y) { animator.drag(x, y); } public void kineticScroll(final int startSpeed, final int direction, final int friction, final float angle) { animator.kineticScroll(startSpeed, direction, friction, angle); } public void stopAnimation() { try { animator.stop(); } catch (Exception e) { Log.e("stopAnimation", "Cannot stop", e); } } /** * Unregister gesture and animation events (there is a max # allowed at any * one time) * */ public void unregister() { GestureRegistrationManager.unregister(canvas, giz); animator.unregister(); } public void updateCanvasSize() { giz.setRectangle(0, 0, canvas.getWidth(), canvas.getHeight()); } /** * Register for gesture and animation events when the parent becomes visible * */ public void register() { GestureRegistrationManager.register(canvas, giz); updateCanvasSize(); GestureRegistrationManager.setListener(canvas, this); animator.register(0, 0, (short) 0, (short) 0, this); } }
When creating a GestureInteractiveZone
object
that uses several gestures, the best way of declaring the gestures
on SDK 2.0 is to use GESTURE_ALL
. However, this will
lead to problems on older SDK 1.1 devices that support the GestureInteractiveZone
class, but not all the gestures.
The following gestures are known to fail on older SDKs:
GESTURE_ALL
GESTURE_PINCH
GESTURE_RECOGNITION_END
GESTURE_RECOGNITION_START
Fortunately, we can catch the exception thrown here, so the
solution is to declare the GestureInteractiveZone
inside a try block, and catch the exception. If there is no need
for the unsupported gestures, it is best not to use them.
The
following example declares a GestureInteractiveZone
with all the supported gestures on SDK 2.0, but falls back to just
a few supported ones on older devices.
// Register for gesturevents final GestureInteractiveZone giz; GestureInteractiveZone tmp = null; try { tmp = new GestureInteractiveZone( GestureInteractiveZone.GESTURE_ALL); } catch (Throwable t){ Log.l.log("Some gesture events not supported.", "", e); tmp = new GestureInteractiveZone( GestureInteractiveZone.GESTURE_DRAG | GestureInteractiveZone.GESTURE_FLICK | GestureInteractiveZone.GESTURE_TAP); } finally { giz = tmp; }
An example app using this technique:
The
Zoom demo under Series 40 UI Component Demos handles gestures
in a backward compatible way. See package com.nokia.example.utils.gesture
for implementation details.
When using the Canvas
class on touch and type and full touch devices, the device assumes
there will be keyboard input, unless otherwise specified. To allow
the user to enable the virtual keyboard, the phone will automatically
add a menu item to open the virtual keyboard. This is visible on the Canvas
as an opaque button, if the MIDlet is viewed in full-screen
mode.
If you bring up a TextEditor when needed, or if there are no actions tied to the keyboard inputs, there is no need for this menu item. You may hide it as follows:
String keyboardType = System.getProperty("com.nokia.keyboard.type"); if (keyboardType.equals("OnekeyBack") || keyboardType.equals("None")) { // full touch or Nokia Asha software platform device detected //Something here com.nokia.mid.ui.VirtualKeyboard.hideOpenKeypadCommand(true); }
An example app using this technique:
WeatherApp example uses an alternate approach with System.getProperty
method to check com.nokia.keyboard.type
property
to hide the virtual keyboard option menu item on full-touch devices.