17d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project/*
27d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project * Copyright (C) 2009 The Android Open Source Project
37d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project *
47d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
57d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project * you may not use this file except in compliance with the License.
67d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project * You may obtain a copy of the License at
77d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project *
87d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
97d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project *
107d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software
117d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
127d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project * See the License for the specific language governing permissions and
147d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project * limitations under the License.
157d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project */
167d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project
177d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project#include "EmojiFactory.h"
187d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project
197d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project#define LOG_TAG "EmojiFactory"
207d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project#include <utils/Log.h>
217d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project#include <utils/Vector.h>
227d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project
237d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project#include <cutils/properties.h>
247d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project
257d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project#include <dlfcn.h>
267d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project#include <stdlib.h>
277d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project#include <string.h>
287d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project#include <pthread.h>
297d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project
307d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project
317d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Projectnamespace android {
327d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project
337d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Projectstatic pthread_once_t g_once = PTHREAD_ONCE_INIT;
347d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Projectstatic Vector<EmojiFactory *> *g_factories = NULL;
357d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Projectstatic Vector<void *> *g_handles = NULL;
367d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project
377d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Projectclass EmojiFactoryManager {
387d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project public:
39e77fc97dc6438110fd5205db2b5c5b799014a0b9Daisuke Miyakawa  void Init();
407d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project  virtual ~EmojiFactoryManager();
417d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project private:
427d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project  void TryRegisterEmojiFactory(const char *library_name);
437d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project};
447d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project
457d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project// Note: I previously did this procedure in the construcor. However,
467d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project// property_get() didn't return a correct value in that context. I guess
477d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project// property_get() does not return correct values before AndroidRuntime
487d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project// instance (or exactly, AppRuntime in instance app_main.cpp) is
497d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project// fully ready (see AndroidRunitem.cpp and app_main.cpp).
507d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project// So, instead of doing this in constructor, I decided this shoud be done
517d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project// when a user requires to EmojiFactory, which makes better sense to me.
52e77fc97dc6438110fd5205db2b5c5b799014a0b9Daisuke Miyakawavoid EmojiFactoryManager::Init() {
537d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project  g_handles = new Vector<void *>();
547d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project  g_factories = new Vector<EmojiFactory *>();
557d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project
567d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project  char *emoji_libraries = new char[PROPERTY_VALUE_MAX];
577d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project  int len = property_get("ro.config.libemoji", emoji_libraries, "");
587d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project  // LOGD("ro.config.libemoji: %s", emoji_libraries);
597d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project  if (len > 0) {
607d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project    char *saveptr, *ptr;
617d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project    ptr = emoji_libraries;
627d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project    while (true) {
637d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project      ptr = strtok_r(ptr, ":", &saveptr);
647d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project      if (NULL == ptr) {
657d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project        break;
667d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project      }
677d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project      TryRegisterEmojiFactory(ptr);
687d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project      ptr = NULL;
697d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project    }
707d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project  }
717d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project
727d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project  delete [] emoji_libraries;
737d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project}
747d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project
757d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Projectvoid EmojiFactoryManager::TryRegisterEmojiFactory(const char *library_name) {
767d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project  void *handle = dlopen(library_name, RTLD_LAZY | RTLD_LOCAL);
77e77fc97dc6438110fd5205db2b5c5b799014a0b9Daisuke Miyakawa  if (handle == NULL) {
78e77fc97dc6438110fd5205db2b5c5b799014a0b9Daisuke Miyakawa    const char* error_str = dlerror();
79e77fc97dc6438110fd5205db2b5c5b799014a0b9Daisuke Miyakawa    if (error_str) {
80e77fc97dc6438110fd5205db2b5c5b799014a0b9Daisuke Miyakawa      error_str = "Unknown reason";
81e77fc97dc6438110fd5205db2b5c5b799014a0b9Daisuke Miyakawa    }
827d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project    LOGE("Failed to load shared library %s: %s", library_name, error_str);
837d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project    return;
847d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project  }
857d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project  EmojiFactory *(*get_emoji_factory)() =
867d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project      reinterpret_cast<EmojiFactory *(*)()>(dlsym(handle,
877d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project                                                  "GetEmojiFactory"));
88e77fc97dc6438110fd5205db2b5c5b799014a0b9Daisuke Miyakawa  if (get_emoji_factory == NULL) {
89e77fc97dc6438110fd5205db2b5c5b799014a0b9Daisuke Miyakawa    const char* error_str = dlerror();
90e77fc97dc6438110fd5205db2b5c5b799014a0b9Daisuke Miyakawa    if (error_str) {
91e77fc97dc6438110fd5205db2b5c5b799014a0b9Daisuke Miyakawa      error_str = "Unknown reason";
92e77fc97dc6438110fd5205db2b5c5b799014a0b9Daisuke Miyakawa    }
937d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project    LOGE("Failed to call GetEmojiFactory: %s", error_str);
947d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project    dlclose(handle);
957d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project    return;
967d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project  }
977d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project
987d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project  EmojiFactory *factory = (*get_emoji_factory)();
997d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project  if (NULL == factory) {
1007d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project    LOGE("Returned factory is NULL");
1017d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project    dlclose(handle);
1027d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project    return;
1037d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project  }
1047d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project
1057d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project  const char *name = factory->Name();
1067d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project
1077d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project  size_t size = g_factories->size();
1087d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project  for (size_t i = 0; i < size; ++i) {
1097d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project    EmojiFactory *f = g_factories->itemAt(i);
1107d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project    if (!strcmp(name, f->Name())) {
1117d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project      LOGE("Same EmojiFactory was found: %s", name);
1127d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project      delete factory;
1137d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project      dlclose(handle);
1147d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project      return;
1157d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project    }
1167d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project  }
1177d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project  g_factories->push(factory);
1187d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project  // dlclose() must not be called here, since returned factory may point to
1197d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project  // static data in the shared library (like "static const char* = "emoji";")
1207d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project  g_handles->push(handle);
1217d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project}
1227d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project
1237d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source ProjectEmojiFactoryManager::~EmojiFactoryManager() {
1247d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project  if (g_factories != NULL) {
1257d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project    size_t size = g_factories->size();
1267d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project    for (size_t i = 0; i < size; ++i) {
1277d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project      delete g_factories->itemAt(i);
1287d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project    }
1297d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project    delete g_factories;
1307d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project  }
1317d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project
1327d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project  if (g_handles != NULL) {
1337d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project    size_t size = g_handles->size();
1347d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project    for (size_t i = 0; i < size; ++i) {
1357d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project      dlclose(g_handles->itemAt(i));
1367d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project    }
1377d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project    delete g_handles;
1387d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project  }
1397d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project}
1407d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project
1417d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Projectstatic EmojiFactoryManager g_registrar;
1427d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project
1437d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Projectstatic void InitializeEmojiFactory() {
144e77fc97dc6438110fd5205db2b5c5b799014a0b9Daisuke Miyakawa  g_registrar.Init();
1457d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project}
1467d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project
1477d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project/* static */
1487d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source ProjectEmojiFactory *EmojiFactory::GetImplementation(const char *name) {
1497d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project  pthread_once(&g_once, InitializeEmojiFactory);
1507d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project  if (NULL == name) {
1517d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project    return NULL;
1527d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project  }
1537d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project  size_t size = g_factories->size();
1547d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project  for (size_t i = 0; i < size; ++i) {
1557d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project    EmojiFactory *factory = g_factories->itemAt(i);
1567d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project    if (!strcmp(name, factory->Name())) {
1577d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project      return factory;
1587d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project    }
1597d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project  }
1607d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project  return NULL;
1617d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project}
1627d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project
1637d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project/* static */
1647d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source ProjectEmojiFactory *EmojiFactory::GetAvailableImplementation() {
1657d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project  pthread_once(&g_once, InitializeEmojiFactory);
1667d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project  size_t size = g_factories->size();
1677d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project  for (size_t i = 0; i < size; ++i) {
1687d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project    EmojiFactory *factory = g_factories->itemAt(i);
1697d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project    return factory;
1707d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project  }
1717d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project  return NULL;
1727d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project}
1737d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project
1747d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project}  // namespace android
1757d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project
1767d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Projectextern "C" android::EmojiFactory *GetImplementation(
1777d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project    const char *name) {
1787d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project  return android::EmojiFactory::GetImplementation(name);
1797d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project}
1807d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project
1817d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Projectextern "C" android::EmojiFactory *GetAvailableImplementation() {
1827d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project  return android::EmojiFactory::GetAvailableImplementation();
1837d814fb9f0fd40667bb0338b7ca2cebfcc331dcThe Android Open Source Project}
184