Home | History | Annotate | Download | only in android
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "qemu-common.h"
     18 #include "utils/panic.h"
     19 #include "android/hw-events.h"
     20 #include "android/charmap.h"
     21 #include "android/multitouch-screen.h"
     22 #include "android/sdk-controller-socket.h"
     23 #include "android/multitouch-port.h"
     24 #include "android/globals.h"  /* for android_hw */
     25 #include "android/opengles.h"
     26 #include "android/utils/misc.h"
     27 #include "android/utils/jpeg-compress.h"
     28 #include "android/utils/debug.h"
     29 
     30 #define  E(...)    derror(__VA_ARGS__)
     31 #define  W(...)    dwarning(__VA_ARGS__)
     32 #define  D(...)    VERBOSE_PRINT(mtport,__VA_ARGS__)
     33 #define  D_ACTIVE  VERBOSE_CHECK(mtport)
     34 
     35 #define TRACE_ON    1
     36 
     37 #if TRACE_ON
     38 #define  T(...)    VERBOSE_PRINT(mtport,__VA_ARGS__)
     39 #else
     40 #define  T(...)
     41 #endif
     42 
     43 /* Timeout (millisec) to use when communicating with SDK controller. */
     44 #define SDKCTL_MT_TIMEOUT      3000
     45 
     46 /*
     47  * Message types used in multi-touch emulation.
     48  */
     49 
     50 /* Pointer move message. */
     51 #define SDKCTL_MT_MOVE                  1
     52 /* First pointer down message. */
     53 #define SDKCTL_MT_FISRT_DOWN            2
     54 /* Last pointer up message. */
     55 #define SDKCTL_MT_LAST_UP               3
     56 /* Pointer down message. */
     57 #define SDKCTL_MT_POINTER_DOWN          4
     58 /* Pointer up message. */
     59 #define SDKCTL_MT_POINTER_UP            5
     60 /* Sends framebuffer update. */
     61 #define SDKCTL_MT_FB_UPDATE             6
     62 /* Framebuffer update has been received. */
     63 #define SDKCTL_MT_FB_UPDATE_RECEIVED    7
     64 /* Framebuffer update has been handled. */
     65 #define SDKCTL_MT_FB_UPDATE_HANDLED     8
     66 
     67 /* Multi-touch port descriptor. */
     68 struct AndroidMTSPort {
     69     /* Caller identifier. */
     70     void*               opaque;
     71     /* Communication socket. */
     72     SDKCtlSocket*       sdkctl;
     73     /* Initialized JPEG compressor instance. */
     74     AJPEGDesc*          jpeg_compressor;
     75     /* Direct packet descriptor for framebuffer updates. */
     76     SDKCtlDirectPacket* fb_packet;
     77 };
     78 
     79 /* Data sent with SDKCTL_MT_QUERY_START */
     80 typedef struct QueryDispData {
     81     /* Width of the emulator display. */
     82     int     width;
     83     /* Height of the emulator display. */
     84     int     height;
     85 } QueryDispData;
     86 
     87 /* Multi-touch event structure received from SDK controller port. */
     88 typedef struct AndroidMTEvent {
     89     /* Pointer identifier. */
     90     int     pid;
     91     /* Pointer 'x' coordinate. */
     92     int     x;
     93     /* Pointer 'y' coordinate. */
     94     int     y;
     95     /* Pointer pressure. */
     96     int     pressure;
     97 } AndroidMTEvent;
     98 
     99 /* Multi-touch pointer descriptor received from SDK controller port. */
    100 typedef struct AndroidMTPtr {
    101     /* Pointer identifier. */
    102     int     pid;
    103 } AndroidMTPtr;
    104 
    105 /* Destroys and frees the descriptor. */
    106 static void
    107 _mts_port_free(AndroidMTSPort* mtsp)
    108 {
    109     if (mtsp != NULL) {
    110         if (mtsp->fb_packet != NULL) {
    111             sdkctl_direct_packet_release(mtsp->fb_packet);
    112         }
    113         if (mtsp->jpeg_compressor != NULL) {
    114             jpeg_compressor_destroy(mtsp->jpeg_compressor);
    115         }
    116         if (mtsp->sdkctl != NULL) {
    117             sdkctl_socket_release(mtsp->sdkctl);
    118         }
    119         AFREE(mtsp);
    120     }
    121 }
    122 
    123 /********************************************************************************
    124  *                          Multi-touch action handlers
    125  *******************************************************************************/
    126 
    127 /*
    128  * Although there are a lot of similarities in the way the handlers below are
    129  * implemented, for the sake of tracing / debugging it's better to have a
    130  * separate handler for each distinctive action.
    131  */
    132 
    133 /* First pointer down event handler. */
    134 static void
    135 _on_action_down(int tracking_id, int x, int y, int pressure)
    136 {
    137     multitouch_update_pointer(MTES_DEVICE, tracking_id, x, y, pressure);
    138 }
    139 
    140 /* Last pointer up event handler. */
    141 static void
    142 _on_action_up(int tracking_id)
    143 {
    144     multitouch_update_pointer(MTES_DEVICE, tracking_id, 0, 0, 0);
    145 }
    146 
    147 /* Pointer down event handler. */
    148 static void
    149 _on_action_pointer_down(int tracking_id, int x, int y, int pressure)
    150 {
    151     multitouch_update_pointer(MTES_DEVICE, tracking_id, x, y, pressure);
    152 }
    153 
    154 /* Pointer up event handler. */
    155 static void
    156 _on_action_pointer_up(int tracking_id)
    157 {
    158     multitouch_update_pointer(MTES_DEVICE, tracking_id, 0, 0, 0);
    159 }
    160 
    161 /* Pointer move event handler. */
    162 static void
    163 _on_action_move(int tracking_id, int x, int y, int pressure)
    164 {
    165     multitouch_update_pointer(MTES_DEVICE, tracking_id, x, y, pressure);
    166 }
    167 
    168 /********************************************************************************
    169  *                          Multi-touch event handlers
    170  *******************************************************************************/
    171 
    172 /* Handles "pointer move" event.
    173  * Param:
    174  *  param - Array of moving pointers.
    175  *  pointers_count - Number of pointers in the array.
    176  */
    177 static void
    178 _on_move(const AndroidMTEvent* param, int pointers_count)
    179 {
    180     int n;
    181     for (n = 0; n < pointers_count; n++, param++) {
    182         T("Multi-touch: MOVE(%d): %d-> %d:%d:%d",
    183           n, param->pid, param->x, param->y, param->pressure);
    184          _on_action_move(param->pid, param->x, param->y, param->pressure);
    185     }
    186 }
    187 
    188 /* Handles "first pointer down" event. */
    189 static void
    190 _on_down(const AndroidMTEvent* param)
    191 {
    192     T("Multi-touch: 1-ST DOWN: %d-> %d:%d:%d",
    193       param->pid, param->x, param->y, param->pressure);
    194     _on_action_down(param->pid, param->x, param->y, param->pressure);
    195 }
    196 
    197 /* Handles "last pointer up" event. */
    198 static void
    199 _on_up(const AndroidMTPtr* param)
    200 {
    201     T("Multi-touch: LAST UP: %d", param->pid);
    202     _on_action_up(param->pid);
    203 }
    204 
    205 /* Handles "next pointer down" event. */
    206 static void
    207 _on_pdown(const AndroidMTEvent* param)
    208 {
    209     T("Multi-touch: DOWN: %d-> %d:%d:%d",
    210       param->pid, param->x, param->y, param->pressure);
    211     _on_action_pointer_down(param->pid, param->x, param->y, param->pressure);
    212 }
    213 
    214 /* Handles "next pointer up" event. */
    215 static void
    216 _on_pup(const AndroidMTPtr* param)
    217 {
    218     T("Multi-touch: UP: %d", param->pid);
    219     _on_action_pointer_up(param->pid);
    220 }
    221 
    222 /********************************************************************************
    223  *                      Device communication callbacks
    224  *******************************************************************************/
    225 
    226 /* A callback that is invoked on SDK controller socket connection events. */
    227 static AsyncIOAction
    228 _on_multitouch_socket_connection(void* opaque,
    229                                  SDKCtlSocket* sdkctl,
    230                                  AsyncIOState status)
    231 {
    232     if (status == ASIO_STATE_FAILED) {
    233         /* Reconnect (after timeout delay) on failures */
    234         if (sdkctl_socket_is_handshake_ok(sdkctl)) {
    235             sdkctl_socket_reconnect(sdkctl, SDKCTL_DEFAULT_TCP_PORT,
    236                                     SDKCTL_MT_TIMEOUT);
    237         }
    238     }
    239     return ASIO_ACTION_DONE;
    240 }
    241 
    242 /* A callback that is invoked on SDK controller port connection events. */
    243 static void
    244 _on_multitouch_port_connection(void* opaque,
    245                                SDKCtlSocket* sdkctl,
    246                                SdkCtlPortStatus status)
    247 {
    248     switch (status) {
    249         case SDKCTL_PORT_CONNECTED:
    250             D("Multi-touch: SDK Controller is connected");
    251             break;
    252 
    253         case SDKCTL_PORT_DISCONNECTED:
    254             D("Multi-touch: SDK Controller is disconnected");
    255             // Disable OpenGLES framebuffer updates.
    256             if (android_hw->hw_gpu_enabled) {
    257                 android_setPostCallback(NULL, NULL);
    258             }
    259             break;
    260 
    261         case SDKCTL_PORT_ENABLED:
    262             D("Multi-touch: SDK Controller port is enabled.");
    263             // Enable OpenGLES framebuffer updates.
    264             if (android_hw->hw_gpu_enabled) {
    265                 android_setPostCallback(multitouch_opengles_fb_update, NULL);
    266             }
    267             /* Refresh (possibly stale) device screen. */
    268             multitouch_refresh_screen();
    269             break;
    270 
    271         case SDKCTL_PORT_DISABLED:
    272             D("Multi-touch: SDK Controller port is disabled.");
    273             // Disable OpenGLES framebuffer updates.
    274             if (android_hw->hw_gpu_enabled) {
    275                 android_setPostCallback(NULL, NULL);
    276             }
    277             break;
    278 
    279         case SDKCTL_HANDSHAKE_CONNECTED:
    280             D("Multi-touch: Handshake succeeded with connected port.");
    281             break;
    282 
    283         case SDKCTL_HANDSHAKE_NO_PORT:
    284             D("Multi-touch: Handshake succeeded with disconnected port.");
    285             break;
    286 
    287         case SDKCTL_HANDSHAKE_DUP:
    288             W("Multi-touch: Handshake failed due to port duplication.");
    289             sdkctl_socket_disconnect(sdkctl);
    290             break;
    291 
    292         case SDKCTL_HANDSHAKE_UNKNOWN_QUERY:
    293             W("Multi-touch: Handshake failed due to unknown query.");
    294             sdkctl_socket_disconnect(sdkctl);
    295             break;
    296 
    297         case SDKCTL_HANDSHAKE_UNKNOWN_RESPONSE:
    298         default:
    299             W("Multi-touch: Handshake failed due to unknown reason.");
    300             sdkctl_socket_disconnect(sdkctl);
    301             break;
    302     }
    303 }
    304 
    305 /* A callback that is invoked when a message is received from the device. */
    306 static void
    307 _on_multitouch_message(void* client_opaque,
    308                        SDKCtlSocket* sdkctl,
    309                        SDKCtlMessage* message,
    310                        int msg_type,
    311                        void* msg_data,
    312                        int msg_size)
    313 {
    314     switch (msg_type) {
    315         case SDKCTL_MT_MOVE: {
    316             assert((msg_size / sizeof(AndroidMTEvent)) && !(msg_size % sizeof(AndroidMTEvent)));
    317             _on_move((const AndroidMTEvent*)msg_data, msg_size / sizeof(AndroidMTEvent));
    318             break;
    319         }
    320 
    321         case SDKCTL_MT_FISRT_DOWN:
    322             assert(msg_size / sizeof(AndroidMTEvent) && !(msg_size % sizeof(AndroidMTEvent)));
    323             _on_down((const AndroidMTEvent*)msg_data);
    324             break;
    325 
    326         case SDKCTL_MT_LAST_UP:
    327             _on_up((const AndroidMTPtr*)msg_data);
    328             break;
    329 
    330         case SDKCTL_MT_POINTER_DOWN:
    331             assert(msg_size / sizeof(AndroidMTEvent) && !(msg_size % sizeof(AndroidMTEvent)));
    332             _on_pdown((const AndroidMTEvent*)msg_data);
    333             break;
    334 
    335         case SDKCTL_MT_POINTER_UP:
    336             _on_pup((const AndroidMTPtr*)msg_data);
    337             break;
    338 
    339         case SDKCTL_MT_FB_UPDATE_RECEIVED:
    340             D("Framebuffer update ACK.");
    341             break;
    342 
    343         case SDKCTL_MT_FB_UPDATE_HANDLED:
    344             D("Framebuffer update handled.");
    345             multitouch_fb_updated();
    346             break;
    347 
    348         default:
    349             W("Multi-touch: Unknown message %d", msg_type);
    350             break;
    351     }
    352 }
    353 
    354 /********************************************************************************
    355  *                          MTS port API
    356  *******************************************************************************/
    357 
    358 AndroidMTSPort*
    359 mts_port_create(void* opaque)
    360 {
    361     AndroidMTSPort* mtsp;
    362 
    363     ANEW0(mtsp);
    364     mtsp->opaque                = opaque;
    365 
    366     /* Initialize default MTS descriptor. */
    367     multitouch_init(mtsp);
    368 
    369     /* Create JPEG compressor. Put message header + MTFrameHeader in front of the
    370      * compressed data. this way we will have entire query ready to be
    371      * transmitted to the device. */
    372     mtsp->jpeg_compressor =
    373         jpeg_compressor_create(sdkctl_message_get_header_size() + sizeof(MTFrameHeader), 4096);
    374 
    375     mtsp->sdkctl = sdkctl_socket_new(SDKCTL_MT_TIMEOUT, "multi-touch",
    376                                      _on_multitouch_socket_connection,
    377                                      _on_multitouch_port_connection,
    378                                      _on_multitouch_message, mtsp);
    379     sdkctl_init_recycler(mtsp->sdkctl, 64, 8);
    380 
    381     /* Create a direct packet that will wrap up framebuffer updates. Note that
    382      * we need to do this after we have initialized the recycler! */
    383     mtsp->fb_packet = sdkctl_direct_packet_new(mtsp->sdkctl);
    384 
    385     /* Now we can initiate connection witm MT port on the device. */
    386     sdkctl_socket_connect(mtsp->sdkctl, SDKCTL_DEFAULT_TCP_PORT,
    387                           SDKCTL_MT_TIMEOUT);
    388 
    389     return mtsp;
    390 }
    391 
    392 void
    393 mts_port_destroy(AndroidMTSPort* mtsp)
    394 {
    395     _mts_port_free(mtsp);
    396 }
    397 
    398 /********************************************************************************
    399  *                       Handling framebuffer updates
    400  *******************************************************************************/
    401 
    402 /* Compresses a framebuffer region into JPEG image.
    403  * Param:
    404  *  mtsp - Multi-touch port descriptor with initialized JPEG compressor.
    405  *  fmt Descriptor for framebuffer region to compress.
    406  *  fb Beginning of the framebuffer.
    407  *  jpeg_quality JPEG compression quality. A number from 1 to 100. Note that
    408  *      value 10 provides pretty decent image for the purpose of multi-touch
    409  *      emulation.
    410  */
    411 static void
    412 _fb_compress(const AndroidMTSPort* mtsp,
    413              const MTFrameHeader* fmt,
    414              const uint8_t* fb,
    415              int jpeg_quality,
    416              int ydir)
    417 {
    418     T("Multi-touch: compressing %d bytes frame buffer", fmt->w * fmt->h * fmt->bpp);
    419 
    420     jpeg_compressor_compress_fb(mtsp->jpeg_compressor, fmt->x, fmt->y, fmt->w,
    421                                 fmt->h, fmt->disp_height, fmt->bpp, fmt->bpl,
    422                                 fb, jpeg_quality, ydir);
    423 }
    424 
    425 int
    426 mts_port_send_frame(AndroidMTSPort* mtsp,
    427                     MTFrameHeader* fmt,
    428                     const uint8_t* fb,
    429                     on_sdkctl_direct_cb cb,
    430                     void* cb_opaque,
    431                     int ydir)
    432 {
    433     /* Make sure that port is connected. */
    434     if (!sdkctl_socket_is_port_ready(mtsp->sdkctl)) {
    435         return -1;
    436     }
    437 
    438     /* Compress framebuffer region. 10% quality seems to be sufficient. */
    439     fmt->format = MTFB_JPEG;
    440     _fb_compress(mtsp, fmt, fb, 10, ydir);
    441 
    442     /* Total size of the update data: header + JPEG image. */
    443     const int update_size =
    444         sizeof(MTFrameHeader) + jpeg_compressor_get_jpeg_size(mtsp->jpeg_compressor);
    445 
    446     /* Update message starts at the beginning of the buffer allocated by the
    447      * compressor's destination manager. */
    448     uint8_t* const msg = (uint8_t*)jpeg_compressor_get_buffer(mtsp->jpeg_compressor);
    449 
    450     /* Initialize message header. */
    451     sdkctl_init_message_header(msg, SDKCTL_MT_FB_UPDATE, update_size);
    452 
    453     /* Copy framebuffer update header to the message. */
    454     memcpy(msg + sdkctl_message_get_header_size(), fmt, sizeof(MTFrameHeader));
    455 
    456     /* Compression rate... */
    457     const float comp_rate = ((float)jpeg_compressor_get_jpeg_size(mtsp->jpeg_compressor) / (fmt->w * fmt->h * fmt->bpp)) * 100;
    458 
    459     /* Zeroing the rectangle in the update header we indicate that it contains
    460      * no updates. */
    461     fmt->x = fmt->y = fmt->w = fmt->h = 0;
    462 
    463     /* Send update to the device. */
    464     sdkctl_direct_packet_send(mtsp->fb_packet, msg, cb, cb_opaque);
    465 
    466     T("Multi-touch: Sent %d bytes in framebuffer update. Compression rate is %.2f%%",
    467       update_size, comp_rate);
    468 
    469     return 0;
    470 }
    471