72
|
1 |
/*
|
|
2 |
* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
|
3 |
* All rights reserved.
|
|
4 |
* This component and the accompanying materials are made available
|
|
5 |
* under the terms of "Eclipse Public License v1.0"
|
|
6 |
* which accompanies this distribution, and is available
|
|
7 |
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
|
|
8 |
*
|
|
9 |
* Initial Contributors:
|
|
10 |
* Nokia Corporation - initial contribution.
|
|
11 |
*
|
|
12 |
* Contributors:
|
|
13 |
*
|
|
14 |
* Description:
|
|
15 |
*
|
|
16 |
*/
|
|
17 |
|
|
18 |
package com.nokia.mid.ui;
|
|
19 |
|
|
20 |
import org.eclipse.swt.widgets.Internal_PackageSupport;
|
|
21 |
import com.nokia.mid.ui.internal.OS;
|
|
22 |
|
|
23 |
|
|
24 |
/**
|
|
25 |
* This class is a Java extension to support tactile feedback (audio, vibra,
|
|
26 |
* piezo, etc.) on touch-enabled devices. Tactile feedback is meant to give user
|
|
27 |
* more clear feeling of touch events, like tapping and dragging. The actual
|
|
28 |
* physical tactile feedback depends on the device tactile feedback
|
|
29 |
* implementation, hardware and device settings. A device may implement the
|
|
30 |
* feedback with different hardware methods, for example, vibra, audio or piezo
|
|
31 |
* hardware.
|
|
32 |
* <p>
|
|
33 |
* The API supports both LCDUI and eSWT UI toolkits.
|
|
34 |
* <p>
|
|
35 |
* Using this class is safe when a device does not support tactile feedback. In
|
|
36 |
* this case methods of this class can be called but this has no effect.
|
|
37 |
* <p>
|
|
38 |
* Tactile feedback can be generated in two ways:
|
|
39 |
* <ul>
|
|
40 |
* <li>By producing direct feedback from the application.</li>
|
|
41 |
* <li>By adding feedback areas to area registry, in which case the feedback
|
|
42 |
* will be produced by the tactile feedback system automatically when the
|
|
43 |
* defined screen area (with defined feedback) is touched.</li>
|
|
44 |
* </ul>
|
|
45 |
* <p>
|
|
46 |
* Direct feedback is given instantly with {@link #directFeedback
|
|
47 |
* directFeedback} specifying the feedback type. Direct feedback can be used
|
|
48 |
* when the user action is not just a tap in a certain area. For example if the
|
|
49 |
* user drags from one menu item to the other the application may give direct
|
|
50 |
* feedback to emphasize focus traverse.
|
|
51 |
* <p>
|
|
52 |
* In case of area registry for eSWT Control, the registry needs to be updated
|
|
53 |
* every time when the size or position of a UI component changes, or when e.g.
|
|
54 |
* a state of a UI component changes in such way that feedback type also
|
|
55 |
* changes. Typically the area update may be implemented in
|
|
56 |
* <code>controlMoved</code> and <code>controlResized</code> methods of
|
|
57 |
* <code>ControlListener</code> interface.
|
|
58 |
* <p>
|
|
59 |
* In case of area registry for LCDUI Canvas or CustomItem no further actions
|
|
60 |
* are required to update tactile feedback areas when a CustomItem is moved in a
|
|
61 |
* Form or when a Canvas is changed due to e.g. orientation switch.
|
|
62 |
* <p>
|
|
63 |
* There are quite tight latency requirements for tactile feedback, and in most
|
|
64 |
* cases feedback should be triggered in less than 30ms from the time when user
|
|
65 |
* touched the screen. For the area registry the feedback system is responsible
|
|
66 |
* of fulfilling this requirement, but in case of direct feedback it is the
|
|
67 |
* responsibility of the user of this API.
|
|
68 |
* <p>
|
|
69 |
* The tactile feedback has 2 different styles: Basic and Sensitive. Each type
|
|
70 |
* is defined in the device settings, not by this API. Each style of feedback is
|
|
71 |
* used in different cases. Typically Basic style is used to emphasize the tap
|
|
72 |
* event, while Sensitive style is used mostly at dragging operations, to
|
|
73 |
* emphasize focus traverse, text selection, etc. Choosing a specific style for
|
|
74 |
* each use case in up to developer, however it is good to follow the behavior
|
|
75 |
* of native applications.
|
|
76 |
* <p>
|
|
77 |
* The goal of the API is to enable user-created UI components to have tactile
|
|
78 |
* feedback. The UI component types supported by the API are limited to
|
|
79 |
* user-defined components only: <code>javax.microedition.lcdui.Canvas</code>,
|
|
80 |
* <code>javax.microedition.lcdui.CustomItem</code>,
|
|
81 |
* <code>org.eclipse.swt.widgets.Control</code>. Other UI components (i.e. List,
|
|
82 |
* TextBox, etc.) get default tactile feedback automatically from the platform.
|
|
83 |
*
|
|
84 |
* @version 0.001
|
|
85 |
* @since 1.2
|
|
86 |
*/
|
|
87 |
|
|
88 |
public class TactileFeedback
|
|
89 |
{
|
|
90 |
|
|
91 |
/**
|
|
92 |
* Constant for specifying basic tactile feedback style. Actual style
|
|
93 |
* behaviour is set through device settings.
|
|
94 |
*/
|
|
95 |
public static final int FEEDBACK_STYLE_BASIC = 1;
|
|
96 |
|
|
97 |
/**
|
|
98 |
* Constant for specifying sensitive tactile feedback style. Actual style
|
|
99 |
* behaviour is set through device settings.
|
|
100 |
*/
|
|
101 |
public static final int FEEDBACK_STYLE_SENSITIVE = 2;
|
|
102 |
|
|
103 |
private final String invalidFeedbackStyleMsg = "Invalid feedback style specified";
|
|
104 |
private final String invalidControlTypeMsg = "Invalid object provided for tactile feedback registration";
|
|
105 |
|
|
106 |
private static final int TYPE_INVALID = 0;
|
|
107 |
private static final int TYPE_ESWT = 1;
|
|
108 |
private static final int TYPE_LCDUI = 2;
|
|
109 |
private static boolean feedbackEnabled;
|
|
110 |
|
|
111 |
/**
|
|
112 |
* Constructs tactile feedback engine object. The object may be used in both
|
|
113 |
* LCDUI and eSWT java UI toolkits. TactileFeedback object must be
|
|
114 |
* constructed before using any tactile feedback methods.
|
|
115 |
*/
|
|
116 |
public TactileFeedback()
|
|
117 |
{
|
|
118 |
}
|
|
119 |
|
|
120 |
/**
|
|
121 |
* Triggers direct tactile feedback of the specified style.
|
|
122 |
*
|
|
123 |
* @param style
|
|
124 |
* The style of the direct feedback. Use predefined values
|
|
125 |
* FEEDBACK_STYLE_BASIC, FEEDBACK_STYLE_SENSITIVE. Actual style
|
|
126 |
* behavior is set through device settings.
|
|
127 |
* @throws IllegalArgumentException
|
|
128 |
* if the style parameter has invalid type.
|
|
129 |
*/
|
|
130 |
public void directFeedback(int style) throws IllegalArgumentException
|
|
131 |
{
|
|
132 |
if ((style != FEEDBACK_STYLE_BASIC)
|
|
133 |
&& (style != FEEDBACK_STYLE_SENSITIVE))
|
|
134 |
throw new IllegalArgumentException(invalidFeedbackStyleMsg);
|
|
135 |
if (org.eclipse.swt.widgets.Display.getCurrent() == null)
|
|
136 |
{
|
|
137 |
final int fStyle = style;
|
|
138 |
com.nokia.mj.impl.nokialcdui.LCDUIInvoker
|
|
139 |
.eSWTUIThreadRunnerSyncExec(new Runnable()
|
|
140 |
{
|
|
141 |
public void run()
|
|
142 |
{
|
|
143 |
OS.MTouchFeedback_InstantFeedback(fStyle);
|
|
144 |
}
|
|
145 |
});
|
|
146 |
|
|
147 |
}
|
|
148 |
else
|
|
149 |
{
|
|
150 |
OS.MTouchFeedback_InstantFeedback(style);
|
|
151 |
}
|
|
152 |
}
|
|
153 |
|
|
154 |
/**
|
|
155 |
* Queries the device if it supports tactile feedback. It is safe to use
|
|
156 |
* this class even if the device does not support tactile feedback. Methods
|
|
157 |
* of this class can be called but this has no effect.
|
|
158 |
*
|
|
159 |
* @return true if the device supports tactile feedback, false otherwise.
|
|
160 |
*/
|
|
161 |
public boolean isTouchFeedbackSupported()
|
|
162 |
{
|
|
163 |
if (org.eclipse.swt.widgets.Display.getCurrent() == null)
|
|
164 |
{
|
|
165 |
com.nokia.mj.impl.nokialcdui.LCDUIInvoker
|
|
166 |
.eSWTUIThreadRunnerSyncExec(new Runnable()
|
|
167 |
{
|
|
168 |
|
|
169 |
public void run()
|
|
170 |
{
|
|
171 |
feedbackEnabled = OS
|
|
172 |
.MTouchFeedback_TouchFeedbackSupported();
|
|
173 |
}
|
|
174 |
});
|
|
175 |
}
|
|
176 |
else
|
|
177 |
{
|
|
178 |
feedbackEnabled = OS.MTouchFeedback_TouchFeedbackSupported();
|
|
179 |
}
|
|
180 |
return feedbackEnabled;
|
|
181 |
}
|
|
182 |
|
|
183 |
/**
|
|
184 |
* Registers area within a UI component for tactile feedback. If areas
|
|
185 |
* overlap then the feedback is given from the last registered area.
|
|
186 |
* {@link #moveFeedbackAreaToFirstPriority moveFeedbackAreaToFirstPriority}
|
|
187 |
* can be used to bring a certain area covered by another area into action.
|
|
188 |
* If an area with specified <code>id</code> is already registered it is
|
|
189 |
* updated. When updating an existing area there is no need to unregister it
|
|
190 |
* before re-registering again with new coordinates and/or feedback style.
|
|
191 |
* The area specified by <code>x</code>, <code>y</code>, <code>width</code>
|
|
192 |
* and <code>height</code> parameters may be located on the screen just
|
|
193 |
* partially.
|
|
194 |
*
|
|
195 |
* <p>
|
|
196 |
* In case of area registry for eSWT Control, the registry needs to be
|
|
197 |
* updated every time when the size or position of a UI component changes,
|
|
198 |
* or when e.g. a state of a UI component changes in such way that feedback
|
|
199 |
* type also changes. Typically the area update may be implemented in
|
|
200 |
* <code>controlMoved</code> and <code>controlResized</code> methods of
|
|
201 |
* <code>ControlListener</code> interface. The update of an area may be
|
|
202 |
* implemented by calling registerFeedbackArea with the same area id but new
|
|
203 |
* coordinates and/or feedback style.
|
|
204 |
* <p>
|
|
205 |
* In case of area registry for LCDUI Canvas or CustomItem no further
|
|
206 |
* actions are required to update tactile feedback areas when a CustomItem
|
|
207 |
* is moved in a Form or when a Canvas is changed due to e.g. orientation
|
|
208 |
* switch.
|
|
209 |
*
|
|
210 |
* @param uiObject
|
|
211 |
* The UI component for tactile feedback registration. Valid
|
|
212 |
* object types are: <code>javax.microedition.lcdui.Canvas</code>
|
|
213 |
* , <code>javax.microedition.lcdui.CustomItem</code>,
|
|
214 |
* <code>org.eclipse.swt.widgets.Control</code>.
|
|
215 |
* @param id
|
|
216 |
* Id of the new tactile feedback area to be registered. Id's are
|
|
217 |
* used to identify particular tactile feedback area within one
|
|
218 |
* UI component. Id's do not need to be consecutive numbers.
|
|
219 |
* @param x
|
|
220 |
* x-coordinate of the top-left corner of tactile feedback
|
|
221 |
* rectangle to register.
|
|
222 |
* @param y
|
|
223 |
* y-coordinate of the top-left corner of tactile feedback
|
|
224 |
* rectangle to register.
|
|
225 |
* @param width
|
|
226 |
* Width of tactile feedback rectangle to register.
|
|
227 |
* @param height
|
|
228 |
* Height of tactile feedback rectangle to register.
|
|
229 |
* @param style
|
|
230 |
* The style of the feedback for specified area. Use predefined
|
|
231 |
* values <code>FEEDBACK_STYLE_BASIC</code>,
|
|
232 |
* <code>FEEDBACK_STYLE_SENSITIVE</code>. Actual style behaviour
|
|
233 |
* is defined through device settings.
|
|
234 |
* @throws IllegalArgumentException
|
|
235 |
* if the uiObject parameter has invalid type.
|
|
236 |
* @throws IllegalArgumentException
|
|
237 |
* if the style parameter has invalid type.
|
|
238 |
*/
|
|
239 |
public void registerFeedbackArea(Object uiObject, int id, int x, int y,
|
|
240 |
int width, int height, int style) throws IllegalArgumentException
|
|
241 |
{
|
|
242 |
int type = controlType(uiObject);
|
|
243 |
if (type == TYPE_INVALID)
|
|
244 |
throw new IllegalArgumentException(invalidControlTypeMsg);
|
|
245 |
|
|
246 |
if ((style != FEEDBACK_STYLE_BASIC)
|
|
247 |
&& (style != FEEDBACK_STYLE_SENSITIVE))
|
|
248 |
throw new IllegalArgumentException(invalidFeedbackStyleMsg);
|
|
249 |
|
|
250 |
int controlHandle = getControlHandle(uiObject);
|
|
251 |
if (type == TYPE_LCDUI)
|
|
252 |
{
|
|
253 |
final int fControlHandle = controlHandle;
|
|
254 |
final int fId = id;
|
|
255 |
final int fX = x;
|
|
256 |
final int fY = y;
|
|
257 |
final int fWidth = width;
|
|
258 |
final int fHeight = height;
|
|
259 |
final int fStyle = style;
|
|
260 |
com.nokia.mj.impl.nokialcdui.LCDUIInvoker
|
|
261 |
.eSWTUIThreadRunnerSyncExec(new Runnable()
|
|
262 |
{
|
|
263 |
|
|
264 |
public void run()
|
|
265 |
{
|
|
266 |
OS.MTouchFeedback_SetFeedbackArea(fControlHandle,
|
|
267 |
fId, fX, fY, fWidth, fHeight, fStyle);
|
|
268 |
}
|
|
269 |
});
|
|
270 |
}
|
|
271 |
else
|
|
272 |
{
|
|
273 |
OS.MTouchFeedback_SetFeedbackArea(controlHandle, id, x, y, width,
|
|
274 |
height, style);
|
|
275 |
}
|
|
276 |
}
|
|
277 |
|
|
278 |
/**
|
|
279 |
* Unregisters tactile feedback area within a UI component.
|
|
280 |
*
|
|
281 |
* @param uiObject
|
|
282 |
* The UI component for tactile feedback area de-registration.
|
|
283 |
* Valid object types are:
|
|
284 |
* <code>javax.microedition.lcdui.Canvas</code>,
|
|
285 |
* <code>javax.microedition.lcdui.CustomItem</code>,
|
|
286 |
* <code>org.eclipse.swt.widgets.Control</code>.
|
|
287 |
* @param id
|
|
288 |
* Id of the tactile feedback area to be unregistered. Id's are
|
|
289 |
* used to identify particular tactile feedback area within one
|
|
290 |
* UI component. If given id was not registered by
|
|
291 |
* {@link #registerFeedbackArea registerFeedbackArea} then the
|
|
292 |
* call has no effect.
|
|
293 |
* @throws IllegalArgumentException
|
|
294 |
* if the uiObject parameter has invalid type.
|
|
295 |
*/
|
|
296 |
public void unregisterFeedbackArea(Object uiObject, int id)
|
|
297 |
throws IllegalArgumentException
|
|
298 |
{
|
|
299 |
|
|
300 |
int type = controlType(uiObject);
|
|
301 |
if (type == TYPE_INVALID)
|
|
302 |
throw new IllegalArgumentException(invalidControlTypeMsg);
|
|
303 |
|
|
304 |
int controlHandle = getControlHandle(uiObject);
|
|
305 |
if (type == TYPE_LCDUI)
|
|
306 |
{
|
|
307 |
final int fControlHandle = controlHandle;
|
|
308 |
final int fId = id;
|
|
309 |
com.nokia.mj.impl.nokialcdui.LCDUIInvoker
|
|
310 |
.eSWTUIThreadRunnerSyncExec(new Runnable()
|
|
311 |
{
|
|
312 |
|
|
313 |
public void run()
|
|
314 |
{
|
|
315 |
OS.MTouchFeedback_RemoveFeedbackArea(
|
|
316 |
fControlHandle, fId);
|
|
317 |
}
|
|
318 |
});
|
|
319 |
}
|
|
320 |
else
|
|
321 |
{
|
|
322 |
OS.MTouchFeedback_RemoveFeedbackArea(controlHandle, id);
|
|
323 |
}
|
|
324 |
|
|
325 |
}
|
|
326 |
|
|
327 |
/**
|
|
328 |
* Removes all tactile feedback for a UI component.
|
|
329 |
*
|
|
330 |
* @param uiObject
|
|
331 |
* The UI component for tactile feedback area de-registration.
|
|
332 |
* Valid object types are:
|
|
333 |
* <code>javax.microedition.lcdui.Canvas</code>,
|
|
334 |
* <code>javax.microedition.lcdui.CustomItem</code>,
|
|
335 |
* <code>org.eclipse.swt.widgets.Control</code>.
|
|
336 |
* @throws IllegalArgumentException
|
|
337 |
* if the uiObject parameter has invalid type.
|
|
338 |
*/
|
|
339 |
public void removeFeedbackForComponent(Object uiObject)
|
|
340 |
{
|
|
341 |
if (isTouchFeedbackSupported() == false)
|
|
342 |
return;
|
|
343 |
|
|
344 |
int type = controlType(uiObject);
|
|
345 |
if (type == TYPE_INVALID)
|
|
346 |
throw new IllegalArgumentException(invalidControlTypeMsg);
|
|
347 |
|
|
348 |
int controlHandle = getControlHandle(uiObject);
|
|
349 |
|
|
350 |
if (type == TYPE_LCDUI)
|
|
351 |
{
|
|
352 |
final int fControlHandle = controlHandle;
|
|
353 |
com.nokia.mj.impl.nokialcdui.LCDUIInvoker
|
|
354 |
.eSWTUIThreadRunnerSyncExec(new Runnable()
|
|
355 |
{
|
|
356 |
|
|
357 |
public void run()
|
|
358 |
{
|
|
359 |
OS.MTouchFeedback_RemoveFeedbackForControl(fControlHandle);
|
|
360 |
}
|
|
361 |
});
|
|
362 |
}
|
|
363 |
else
|
|
364 |
{
|
|
365 |
OS.MTouchFeedback_RemoveFeedbackForControl(controlHandle);
|
|
366 |
}
|
|
367 |
|
|
368 |
}
|
|
369 |
|
|
370 |
/**
|
|
371 |
* Moves the specified tactile feedback area to first priority. Priority is
|
|
372 |
* significant in case of overlapping tactile feedback areas. If the tactile
|
|
373 |
* feedback styles of registered areas are different, the feedback from
|
|
374 |
* first-priority area will be given.
|
|
375 |
*
|
|
376 |
* @param uiObject
|
|
377 |
* The UI component for tactile feedback area de-registration.
|
|
378 |
* Valid object types are:
|
|
379 |
* <code>javax.microedition.lcdui.Canvas</code>,
|
|
380 |
* <code>javax.microedition.lcdui.CustomItem</code>,
|
|
381 |
* <code>org.eclipse.swt.widgets.Control</code>.
|
|
382 |
* @param id
|
|
383 |
* Id of the tactile feedback area to be unregistered. Id's are
|
|
384 |
* used to identify particular tactile feedback area within one
|
|
385 |
* UI component. If given id was not registered by
|
|
386 |
* {@link #registerFeedbackArea registerFeedbackArea} then the
|
|
387 |
* call has no effect.
|
|
388 |
* @throws IllegalArgumentException
|
|
389 |
* if the uiObject parameter has invalid type.
|
|
390 |
*/
|
|
391 |
public void moveFeedbackAreaToFirstPriority(Object uiObject, int id)
|
|
392 |
{
|
|
393 |
if (isTouchFeedbackSupported() == false)
|
|
394 |
return;
|
|
395 |
|
|
396 |
int type = controlType(uiObject);
|
|
397 |
if (type == TYPE_INVALID)
|
|
398 |
throw new IllegalArgumentException(invalidControlTypeMsg);
|
|
399 |
|
|
400 |
int controlHandle = getControlHandle(uiObject);
|
|
401 |
if (type == TYPE_LCDUI)
|
|
402 |
{
|
|
403 |
final int fControlHandle = controlHandle;
|
|
404 |
final int fId = id;
|
|
405 |
com.nokia.mj.impl.nokialcdui.LCDUIInvoker
|
|
406 |
.eSWTUIThreadRunnerSyncExec(new Runnable()
|
|
407 |
{
|
|
408 |
|
|
409 |
public void run()
|
|
410 |
{
|
|
411 |
OS.MTouchFeedback_MoveFeedbackAreaToFirstPriority(
|
|
412 |
fControlHandle, fId);
|
|
413 |
}
|
|
414 |
});
|
|
415 |
}
|
|
416 |
else
|
|
417 |
{
|
|
418 |
OS.MTouchFeedback_MoveFeedbackAreaToFirstPriority(
|
|
419 |
controlHandle, id);
|
|
420 |
}
|
|
421 |
|
|
422 |
}
|
|
423 |
|
|
424 |
|
|
425 |
private int controlType(Object obj)
|
|
426 |
{
|
|
427 |
if ((obj instanceof javax.microedition.lcdui.Canvas)
|
|
428 |
|| (obj instanceof javax.microedition.lcdui.CustomItem))
|
|
429 |
{
|
|
430 |
return TYPE_LCDUI;
|
|
431 |
}
|
|
432 |
else if ((obj instanceof org.eclipse.swt.widgets.Control))
|
|
433 |
{
|
|
434 |
return TYPE_ESWT;
|
|
435 |
}
|
|
436 |
return TYPE_INVALID;
|
|
437 |
}
|
|
438 |
|
|
439 |
private int getControlHandle(Object uiObject)
|
|
440 |
{
|
|
441 |
int controlHandle = 0;
|
|
442 |
org.eclipse.swt.widgets.Control eSwtControl = null;
|
|
443 |
if (uiObject instanceof javax.microedition.lcdui.Canvas
|
|
444 |
|| uiObject instanceof javax.microedition.lcdui.CustomItem)
|
|
445 |
{
|
|
446 |
eSwtControl = com.nokia.mj.impl.nokialcdui.LCDUIInvoker
|
|
447 |
.getEswtControl(uiObject);
|
|
448 |
}
|
|
449 |
else if (uiObject instanceof org.eclipse.swt.widgets.Control)
|
|
450 |
{
|
|
451 |
eSwtControl = (org.eclipse.swt.widgets.Control) uiObject;
|
|
452 |
}
|
|
453 |
|
|
454 |
if (eSwtControl != null)
|
|
455 |
{
|
|
456 |
controlHandle = Internal_PackageSupport.topHandle(eSwtControl);
|
|
457 |
}
|
|
458 |
return controlHandle;
|
|
459 |
}
|
|
460 |
|
|
461 |
}
|