Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright (C) 2010 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 <stdlib.h>
     18 
     19 #include "errno.h"
     20 #include "com_android_nfc.h"
     21 #include "com_android_nfc_list.h"
     22 #include "phLibNfcStatus.h"
     23 
     24 /*
     25  * JNI Initialization
     26  */
     27 jint JNI_OnLoad(JavaVM *jvm, void *reserved)
     28 {
     29    JNIEnv *e;
     30 
     31    LOGD("NFC Service : loading JNI\n");
     32 
     33    // Check JNI version
     34    if(jvm->GetEnv((void **)&e, JNI_VERSION_1_6))
     35       return JNI_ERR;
     36 
     37    android::vm = jvm;
     38 
     39    if (android::register_com_android_nfc_NativeNfcManager(e) == -1)
     40       return JNI_ERR;
     41    if (android::register_com_android_nfc_NativeNfcTag(e) == -1)
     42       return JNI_ERR;
     43    if (android::register_com_android_nfc_NativeP2pDevice(e) == -1)
     44       return JNI_ERR;
     45    if (android::register_com_android_nfc_NativeLlcpSocket(e) == -1)
     46       return JNI_ERR;
     47    if (android::register_com_android_nfc_NativeLlcpConnectionlessSocket(e) == -1)
     48       return JNI_ERR;
     49    if (android::register_com_android_nfc_NativeLlcpServiceSocket(e) == -1)
     50       return JNI_ERR;
     51    if (android::register_com_android_nfc_NativeNfcSecureElement(e) == -1)
     52       return JNI_ERR;
     53 
     54    return JNI_VERSION_1_6;
     55 }
     56 
     57 namespace android {
     58 
     59 extern struct nfc_jni_native_data *exported_nat;
     60 
     61 JavaVM *vm;
     62 
     63 /*
     64  * JNI Utils
     65  */
     66 JNIEnv *nfc_get_env()
     67 {
     68     JNIEnv *e;
     69     if (vm->GetEnv((void **)&e, JNI_VERSION_1_6) != JNI_OK) {
     70         LOGE("Current thread is not attached to VM");
     71         abort();
     72     }
     73     return e;
     74 }
     75 
     76 bool nfc_cb_data_init(nfc_jni_callback_data* pCallbackData, void* pContext)
     77 {
     78    /* Create semaphore */
     79    if(sem_init(&pCallbackData->sem, 0, 0) == -1)
     80    {
     81       LOGE("Semaphore creation failed (errno=0x%08x)", errno);
     82       return false;
     83    }
     84 
     85    /* Set default status value */
     86    pCallbackData->status = NFCSTATUS_FAILED;
     87 
     88    /* Copy the context */
     89    pCallbackData->pContext = pContext;
     90 
     91    /* Add to active semaphore list */
     92    if (!listAdd(&nfc_jni_get_monitor()->sem_list, pCallbackData))
     93    {
     94       LOGE("Failed to add the semaphore to the list");
     95    }
     96 
     97    return true;
     98 }
     99 
    100 void nfc_cb_data_deinit(nfc_jni_callback_data* pCallbackData)
    101 {
    102    /* Destroy semaphore */
    103    if (sem_destroy(&pCallbackData->sem))
    104    {
    105       LOGE("Failed to destroy semaphore (errno=0x%08x)", errno);
    106    }
    107 
    108    /* Remove from active semaphore list */
    109    if (!listRemove(&nfc_jni_get_monitor()->sem_list, pCallbackData))
    110    {
    111       LOGE("Failed to remove semaphore from the list");
    112    }
    113 
    114 }
    115 
    116 void nfc_cb_data_releaseAll()
    117 {
    118    nfc_jni_callback_data* pCallbackData;
    119 
    120    while (listGetAndRemoveNext(&nfc_jni_get_monitor()->sem_list, (void**)&pCallbackData))
    121    {
    122       pCallbackData->status = NFCSTATUS_FAILED;
    123       sem_post(&pCallbackData->sem);
    124    }
    125 }
    126 
    127 int nfc_jni_cache_object(JNIEnv *e, const char *clsname,
    128    jobject *cached_obj)
    129 {
    130    jclass cls;
    131    jobject obj;
    132    jmethodID ctor;
    133 
    134    cls = e->FindClass(clsname);
    135    if(cls == NULL)
    136    {
    137       return -1;
    138       LOGD("Find class error\n");
    139    }
    140 
    141 
    142    ctor = e->GetMethodID(cls, "<init>", "()V");
    143 
    144    obj = e->NewObject(cls, ctor);
    145    if(obj == NULL)
    146    {
    147       return -1;
    148       LOGD("Create object error\n");
    149    }
    150 
    151    *cached_obj = e->NewGlobalRef(obj);
    152    if(*cached_obj == NULL)
    153    {
    154       e->DeleteLocalRef(obj);
    155       LOGD("Global ref error\n");
    156       return -1;
    157    }
    158 
    159    e->DeleteLocalRef(obj);
    160 
    161    return 0;
    162 }
    163 
    164 
    165 struct nfc_jni_native_data* nfc_jni_get_nat(JNIEnv *e, jobject o)
    166 {
    167    jclass c;
    168    jfieldID f;
    169 
    170    /* Retrieve native structure address */
    171    c = e->GetObjectClass(o);
    172    f = e->GetFieldID(c, "mNative", "I");
    173    return (struct nfc_jni_native_data*)e->GetIntField(o, f);
    174 }
    175 
    176 struct nfc_jni_native_data* nfc_jni_get_nat_ext(JNIEnv *e)
    177 {
    178    return exported_nat;
    179 }
    180 
    181 static nfc_jni_native_monitor_t *nfc_jni_native_monitor = NULL;
    182 
    183 nfc_jni_native_monitor_t* nfc_jni_init_monitor(void)
    184 {
    185 
    186    pthread_mutexattr_t recursive_attr;
    187 
    188    pthread_mutexattr_init(&recursive_attr);
    189    pthread_mutexattr_settype(&recursive_attr, PTHREAD_MUTEX_RECURSIVE_NP);
    190 
    191    if(nfc_jni_native_monitor == NULL)
    192    {
    193       nfc_jni_native_monitor = (nfc_jni_native_monitor_t*)malloc(sizeof(nfc_jni_native_monitor_t));
    194    }
    195 
    196    if(nfc_jni_native_monitor != NULL)
    197    {
    198       memset(nfc_jni_native_monitor, 0, sizeof(nfc_jni_native_monitor_t));
    199 
    200       if(pthread_mutex_init(&nfc_jni_native_monitor->reentrance_mutex, &recursive_attr) == -1)
    201       {
    202          LOGE("NFC Manager Reentrance Mutex creation returned 0x%08x", errno);
    203          return NULL;
    204       }
    205 
    206       if(pthread_mutex_init(&nfc_jni_native_monitor->concurrency_mutex, NULL) == -1)
    207       {
    208          LOGE("NFC Manager Concurrency Mutex creation returned 0x%08x", errno);
    209          return NULL;
    210       }
    211 
    212       if(!listInit(&nfc_jni_native_monitor->sem_list))
    213       {
    214          LOGE("NFC Manager Semaphore List creation failed");
    215          return NULL;
    216       }
    217 
    218       LIST_INIT(&nfc_jni_native_monitor->incoming_socket_head);
    219 
    220       if(pthread_mutex_init(&nfc_jni_native_monitor->incoming_socket_mutex, NULL) == -1)
    221       {
    222          LOGE("NFC Manager incoming socket mutex creation returned 0x%08x", errno);
    223          return NULL;
    224       }
    225 
    226       if(pthread_cond_init(&nfc_jni_native_monitor->incoming_socket_cond, NULL) == -1)
    227       {
    228          LOGE("NFC Manager incoming socket condition creation returned 0x%08x", errno);
    229          return NULL;
    230       }
    231 
    232 }
    233 
    234    return nfc_jni_native_monitor;
    235 }
    236 
    237 nfc_jni_native_monitor_t* nfc_jni_get_monitor(void)
    238 {
    239    return nfc_jni_native_monitor;
    240 }
    241 
    242 
    243 phLibNfc_Handle nfc_jni_get_p2p_device_handle(JNIEnv *e, jobject o)
    244 {
    245    jclass c;
    246    jfieldID f;
    247 
    248    c = e->GetObjectClass(o);
    249    f = e->GetFieldID(c, "mHandle", "I");
    250 
    251    return e->GetIntField(o, f);
    252 }
    253 
    254 jshort nfc_jni_get_p2p_device_mode(JNIEnv *e, jobject o)
    255 {
    256    jclass c;
    257    jfieldID f;
    258 
    259    c = e->GetObjectClass(o);
    260    f = e->GetFieldID(c, "mMode", "S");
    261 
    262    return e->GetShortField(o, f);
    263 }
    264 
    265 
    266 int nfc_jni_get_connected_tech_index(JNIEnv *e, jobject o)
    267 {
    268 
    269    jclass c;
    270    jfieldID f;
    271 
    272    c = e->GetObjectClass(o);
    273    f = e->GetFieldID(c, "mConnectedTechnology", "I");
    274 
    275    return e->GetIntField(o, f);
    276 
    277 }
    278 
    279 jint nfc_jni_get_connected_technology(JNIEnv *e, jobject o)
    280 {
    281    jclass c;
    282    jfieldID f;
    283    int connectedTech = -1;
    284 
    285    int connectedTechIndex = nfc_jni_get_connected_tech_index(e,o);
    286    jintArray techTypes = nfc_jni_get_nfc_tag_type(e, o);
    287 
    288    if ((connectedTechIndex != -1) && (techTypes != NULL) &&
    289            (connectedTechIndex < e->GetArrayLength(techTypes))) {
    290        jint* technologies = e->GetIntArrayElements(techTypes, 0);
    291        if (technologies != NULL) {
    292            connectedTech = technologies[connectedTechIndex];
    293            e->ReleaseIntArrayElements(techTypes, technologies, JNI_ABORT);
    294        }
    295    }
    296 
    297    return connectedTech;
    298 
    299 }
    300 
    301 jint nfc_jni_get_connected_technology_libnfc_type(JNIEnv *e, jobject o)
    302 {
    303    jclass c;
    304    jfieldID f;
    305    jint connectedLibNfcType = -1;
    306 
    307    int connectedTechIndex = nfc_jni_get_connected_tech_index(e,o);
    308    c = e->GetObjectClass(o);
    309    f = e->GetFieldID(c, "mTechLibNfcTypes", "[I");
    310    jintArray libNfcTypes =  (jintArray) e->GetObjectField(o, f);
    311 
    312    if ((connectedTechIndex != -1) && (libNfcTypes != NULL) &&
    313            (connectedTechIndex < e->GetArrayLength(libNfcTypes))) {
    314        jint* types = e->GetIntArrayElements(libNfcTypes, 0);
    315        if (types != NULL) {
    316            connectedLibNfcType = types[connectedTechIndex];
    317            e->ReleaseIntArrayElements(libNfcTypes, types, JNI_ABORT);
    318        }
    319    }
    320    return connectedLibNfcType;
    321 
    322 }
    323 
    324 phLibNfc_Handle nfc_jni_get_connected_handle(JNIEnv *e, jobject o)
    325 {
    326    jclass c;
    327    jfieldID f;
    328    phLibNfc_Handle connectedHandle = -1;
    329 
    330    int connectedTechIndex = nfc_jni_get_connected_tech_index(e,o);
    331    c = e->GetObjectClass(o);
    332    f = e->GetFieldID(c, "mTechHandles", "[I");
    333    jintArray techHandles =  (jintArray) e->GetObjectField(o, f);
    334 
    335    if ((connectedTechIndex != -1) && (techHandles != NULL) &&
    336            (connectedTechIndex < e->GetArrayLength(techHandles))) {
    337        jint* handles = e->GetIntArrayElements(techHandles, 0);
    338        if (handles != NULL) {
    339            connectedHandle = handles[connectedTechIndex];
    340            e->ReleaseIntArrayElements(techHandles, handles, JNI_ABORT);
    341        }
    342    }
    343    return connectedHandle;
    344 
    345 }
    346 
    347 phLibNfc_Handle nfc_jni_get_nfc_socket_handle(JNIEnv *e, jobject o)
    348 {
    349    jclass c;
    350    jfieldID f;
    351 
    352    c = e->GetObjectClass(o);
    353    f = e->GetFieldID(c, "mHandle", "I");
    354 
    355    return e->GetIntField(o, f);
    356 }
    357 
    358 jintArray nfc_jni_get_nfc_tag_type(JNIEnv *e, jobject o)
    359 {
    360   jclass c;
    361   jfieldID f;
    362   jintArray techtypes;
    363 
    364   c = e->GetObjectClass(o);
    365   f = e->GetFieldID(c, "mTechList","[I");
    366 
    367   /* Read the techtypes  */
    368   techtypes = (jintArray) e->GetObjectField(o, f);
    369 
    370   return techtypes;
    371 }
    372 
    373 
    374 
    375 //Display status code
    376 const char* nfc_jni_get_status_name(NFCSTATUS status)
    377 {
    378    #define STATUS_ENTRY(status) { status, #status }
    379 
    380    struct status_entry {
    381       NFCSTATUS   code;
    382       const char  *name;
    383    };
    384 
    385    const struct status_entry sNameTable[] = {
    386       STATUS_ENTRY(NFCSTATUS_SUCCESS),
    387       STATUS_ENTRY(NFCSTATUS_FAILED),
    388       STATUS_ENTRY(NFCSTATUS_INVALID_PARAMETER),
    389       STATUS_ENTRY(NFCSTATUS_INSUFFICIENT_RESOURCES),
    390       STATUS_ENTRY(NFCSTATUS_TARGET_LOST),
    391       STATUS_ENTRY(NFCSTATUS_INVALID_HANDLE),
    392       STATUS_ENTRY(NFCSTATUS_MULTIPLE_TAGS),
    393       STATUS_ENTRY(NFCSTATUS_ALREADY_REGISTERED),
    394       STATUS_ENTRY(NFCSTATUS_FEATURE_NOT_SUPPORTED),
    395       STATUS_ENTRY(NFCSTATUS_SHUTDOWN),
    396       STATUS_ENTRY(NFCSTATUS_ABORTED),
    397       STATUS_ENTRY(NFCSTATUS_REJECTED ),
    398       STATUS_ENTRY(NFCSTATUS_NOT_INITIALISED),
    399       STATUS_ENTRY(NFCSTATUS_PENDING),
    400       STATUS_ENTRY(NFCSTATUS_BUFFER_TOO_SMALL),
    401       STATUS_ENTRY(NFCSTATUS_ALREADY_INITIALISED),
    402       STATUS_ENTRY(NFCSTATUS_BUSY),
    403       STATUS_ENTRY(NFCSTATUS_TARGET_NOT_CONNECTED),
    404       STATUS_ENTRY(NFCSTATUS_MULTIPLE_PROTOCOLS),
    405       STATUS_ENTRY(NFCSTATUS_DESELECTED),
    406       STATUS_ENTRY(NFCSTATUS_INVALID_DEVICE),
    407       STATUS_ENTRY(NFCSTATUS_MORE_INFORMATION),
    408       STATUS_ENTRY(NFCSTATUS_RF_TIMEOUT),
    409       STATUS_ENTRY(NFCSTATUS_RF_ERROR),
    410       STATUS_ENTRY(NFCSTATUS_BOARD_COMMUNICATION_ERROR),
    411       STATUS_ENTRY(NFCSTATUS_INVALID_STATE),
    412       STATUS_ENTRY(NFCSTATUS_NOT_REGISTERED),
    413       STATUS_ENTRY(NFCSTATUS_RELEASED),
    414       STATUS_ENTRY(NFCSTATUS_NOT_ALLOWED),
    415       STATUS_ENTRY(NFCSTATUS_INVALID_REMOTE_DEVICE),
    416       STATUS_ENTRY(NFCSTATUS_SMART_TAG_FUNC_NOT_SUPPORTED),
    417       STATUS_ENTRY(NFCSTATUS_READ_FAILED),
    418       STATUS_ENTRY(NFCSTATUS_WRITE_FAILED),
    419       STATUS_ENTRY(NFCSTATUS_NO_NDEF_SUPPORT),
    420       STATUS_ENTRY(NFCSTATUS_EOF_NDEF_CONTAINER_REACHED),
    421       STATUS_ENTRY(NFCSTATUS_INVALID_RECEIVE_LENGTH),
    422       STATUS_ENTRY(NFCSTATUS_INVALID_FORMAT),
    423       STATUS_ENTRY(NFCSTATUS_INSUFFICIENT_STORAGE),
    424       STATUS_ENTRY(NFCSTATUS_FORMAT_ERROR),
    425    };
    426 
    427    int i = sizeof(sNameTable)/sizeof(status_entry);
    428 
    429    while(i>0)
    430    {
    431       i--;
    432       if (sNameTable[i].code == PHNFCSTATUS(status))
    433       {
    434          return sNameTable[i].name;
    435       }
    436    }
    437 
    438    return "UNKNOWN";
    439 }
    440 
    441 int addTechIfNeeded(int *techList, int* handleList, int* typeList, int listSize,
    442         int maxListSize, int techToAdd, int handleToAdd, int typeToAdd) {
    443     bool found = false;
    444     for (int i = 0; i < listSize; i++) {
    445         if (techList[i] == techToAdd) {
    446             found = true;
    447             break;
    448         }
    449     }
    450     if (!found && listSize < maxListSize) {
    451         techList[listSize] = techToAdd;
    452         handleList[listSize] = handleToAdd;
    453         typeList[listSize] = typeToAdd;
    454         return listSize + 1;
    455     }
    456     else {
    457         return listSize;
    458     }
    459 }
    460 
    461 
    462 #define MAX_NUM_TECHNOLOGIES 32
    463 
    464 /*
    465  *  Utility to get a technology tree and a corresponding handle list from a detected tag.
    466  */
    467 void nfc_jni_get_technology_tree(JNIEnv* e, phLibNfc_RemoteDevList_t* devList,
    468         uint8_t count, jintArray* techList, jintArray* handleList,
    469         jintArray* libnfcTypeList)
    470 {
    471    int technologies[MAX_NUM_TECHNOLOGIES];
    472    int handles[MAX_NUM_TECHNOLOGIES];
    473    int libnfctypes[MAX_NUM_TECHNOLOGIES];
    474 
    475    int index = 0;
    476    // TODO: This counts from up to down because on multi-protocols, the
    477    // ISO handle is usually the second, and we prefer the ISO. Should implement
    478    // a method to find the "preferred handle order" and use that instead,
    479    // since we shouldn't have dependencies on the tech list ordering.
    480    for (int target = count - 1; target >= 0; target--) {
    481        int type = devList[target].psRemoteDevInfo->RemDevType;
    482        int handle = devList[target].hTargetDev;
    483        switch (type)
    484        {
    485           case phNfc_eISO14443_A_PICC:
    486           case phNfc_eISO14443_4A_PICC:
    487             {
    488               index = addTechIfNeeded(technologies, handles, libnfctypes, index,
    489                       MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type);
    490               index = addTechIfNeeded(technologies, handles, libnfctypes, index,
    491                       MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3A, handle, type);
    492               break;
    493             }
    494           case phNfc_eISO14443_4B_PICC:
    495             {
    496               index = addTechIfNeeded(technologies, handles, libnfctypes, index,
    497                       MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type);
    498               index = addTechIfNeeded(technologies, handles, libnfctypes, index,
    499                       MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3B, handle, type);
    500             }break;
    501           case phNfc_eISO14443_3A_PICC:
    502             {
    503               index = addTechIfNeeded(technologies, handles, libnfctypes,
    504                       index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3A, handle, type);
    505             }break;
    506           case phNfc_eISO14443_B_PICC:
    507             {
    508               // TODO a bug in libnfc will cause 14443-3B only cards
    509               // to be returned as this type as well, but these cards
    510               // are very rare. Hence assume it's -4B
    511               index = addTechIfNeeded(technologies, handles, libnfctypes,
    512                       index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_4, handle, type);
    513               index = addTechIfNeeded(technologies, handles, libnfctypes,
    514                       index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3B, handle, type);
    515             }break;
    516           case phNfc_eISO15693_PICC:
    517             {
    518               index = addTechIfNeeded(technologies, handles, libnfctypes,
    519                       index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO15693, handle, type);
    520             }break;
    521           case phNfc_eMifare_PICC:
    522             {
    523               // We don't want to be too clever here; libnfc has already determined
    524               // it's a Mifare, so we only check for UL, for all other tags
    525               // we assume it's a mifare classic. This should make us more
    526               // future-proof.
    527               int sak = devList[target].psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak;
    528               switch(sak)
    529               {
    530                 case 0x00:
    531                   // could be UL or UL-C
    532                   index = addTechIfNeeded(technologies, handles, libnfctypes,
    533                           index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_MIFARE_UL, handle, type);
    534                   index = addTechIfNeeded(technologies, handles, libnfctypes,
    535                           index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3A, handle, type);
    536                   break;
    537                 default:
    538                   index = addTechIfNeeded(technologies, handles, libnfctypes,
    539                           index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_MIFARE_CLASSIC, handle, type);
    540                   index = addTechIfNeeded(technologies, handles, libnfctypes,
    541                           index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3A, handle, type);
    542                   break;
    543               }
    544             }break;
    545           case phNfc_eFelica_PICC:
    546             {
    547               index = addTechIfNeeded(technologies, handles, libnfctypes,
    548                       index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_FELICA, handle, type);
    549             }break;
    550           case phNfc_eJewel_PICC:
    551             {
    552               // Jewel represented as NfcA
    553               index = addTechIfNeeded(technologies, handles, libnfctypes,
    554                       index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_ISO14443_3A, handle, type);
    555             }break;
    556           default:
    557             {
    558               index = addTechIfNeeded(technologies, handles, libnfctypes,
    559                       index, MAX_NUM_TECHNOLOGIES, TARGET_TYPE_UNKNOWN, handle, type);
    560             }
    561         }
    562    }
    563 
    564    // Build the Java arrays
    565    if (techList != NULL) {
    566        *techList = e->NewIntArray(index);
    567        jint* techItems = e->GetIntArrayElements(*techList, NULL);
    568        for (int i = 0; i < index; i++) {
    569            techItems[i] = technologies[i];
    570        }
    571        e->ReleaseIntArrayElements(*techList, techItems, 0);
    572    }
    573 
    574    if (handleList != NULL) {
    575        *handleList = e->NewIntArray(index);
    576        jint* handleItems = e->GetIntArrayElements(*handleList, NULL);
    577        for (int i = 0; i < index; i++) {
    578            handleItems[i] = handles[i];
    579        }
    580        e->ReleaseIntArrayElements(*handleList, handleItems, 0);
    581    }
    582 
    583    if (libnfcTypeList != NULL) {
    584        *libnfcTypeList = e->NewIntArray(index);
    585 
    586        jint* typeItems = e->GetIntArrayElements(*libnfcTypeList, NULL);
    587        for (int i = 0; i < index; i++) {
    588            typeItems[i] = libnfctypes[i];
    589        }
    590        e->ReleaseIntArrayElements(*libnfcTypeList, typeItems, 0);
    591    }
    592 }
    593 
    594 } // namespace android
    595