javauis/nokiauiapi_qt/javasrc_j2me/com/nokia/mid/ui/TactileFeedback.java
changeset 72 1f0034e370aa
child 78 71ad690e91f5
equal deleted inserted replaced
67:63b81d807542 72:1f0034e370aa
       
     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 }