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