android_emoji_EmojiFactory.cpp revision c81c43991c3522451dbea1743a33d8f7e5446979
1#include "SkTypes.h"
2#include "SkImageDecoder.h"
3
4#define LOG_TAG "EmojiFactory_jni"
5#include <utils/Log.h>
6#include <utils/String8.h>
7
8#include "EmojiFactory.h"
9#include <nativehelper/JNIHelp.h>
10
11#include <dlfcn.h>
12// #include <pthread.h>
13
14namespace android {
15
16class EmojiFactoryCaller {
17 public:
18  EmojiFactoryCaller() {}
19  virtual ~EmojiFactoryCaller();
20  bool Init();
21  EmojiFactory *TryCallGetImplementation(const char* name);
22  EmojiFactory *TryCallGetAvailableImplementation();
23 private:
24  void *m_handle;
25  EmojiFactory *(*m_get_implementation)(const char*);
26  EmojiFactory *(*m_get_available_implementation)();
27};
28
29bool EmojiFactoryCaller::Init() {
30  const char* error_msg;
31  m_handle = dlopen("libemoji.so", RTLD_LAZY | RTLD_LOCAL);
32
33  if (m_handle == NULL) {
34    error_msg = "Failed to load libemoji.so";
35    goto FAIL;
36  }
37
38  m_get_implementation =
39      reinterpret_cast<EmojiFactory *(*)(const char*)>(
40          dlsym(m_handle, "GetImplementation"));
41  if (m_get_implementation == NULL) {
42    error_msg = "Failed to get symbol of GetImplementation";
43    goto FAIL;
44  }
45
46  m_get_available_implementation =
47      reinterpret_cast<EmojiFactory *(*)()>(
48          dlsym(m_handle,"GetAvailableImplementation"));
49  if (m_get_available_implementation == NULL) {
50    error_msg = "Failed to get symbol of GetAvailableImplementation";
51    goto FAIL;
52  }
53
54  return true;
55
56FAIL:
57  const char* error_str = dlerror();
58  if (error_str == NULL) {
59    error_str = "unknown reason";
60  }
61
62  LOGE("%s: %s", error_msg, error_str);
63  if (m_handle != NULL) {
64    dlclose(m_handle);
65    m_handle = NULL;
66  }
67  return false;
68}
69
70EmojiFactoryCaller::~EmojiFactoryCaller() {
71  if (m_handle) {
72    dlclose(m_handle);
73  }
74}
75
76EmojiFactory *EmojiFactoryCaller::TryCallGetImplementation(
77    const char* name) {
78  if (NULL == m_handle) {
79    return NULL;
80  }
81  return m_get_implementation(name);
82}
83
84EmojiFactory *EmojiFactoryCaller::TryCallGetAvailableImplementation() {
85  if (NULL == m_handle) {
86    return NULL;
87  }
88  return m_get_available_implementation();
89}
90
91static EmojiFactoryCaller* gCaller;
92static pthread_once_t g_once = PTHREAD_ONCE_INIT;
93static bool lib_emoji_factory_is_ready;
94
95static jclass    gString_class;
96
97static jclass    gBitmap_class;
98static jmethodID gBitmap_constructorMethodID;
99
100static jclass    gEmojiFactory_class;
101static jmethodID gEmojiFactory_constructorMethodID;
102
103static void InitializeCaller() {
104  gCaller = new EmojiFactoryCaller();
105  lib_emoji_factory_is_ready = gCaller->Init();
106}
107
108static jobject create_java_EmojiFactory(
109    JNIEnv* env, EmojiFactory* factory, jstring name) {
110  jobject obj = env->AllocObject(gEmojiFactory_class);
111  if (obj) {
112    env->CallVoidMethod(obj, gEmojiFactory_constructorMethodID,
113                        (jint)factory, name);
114    if (env->ExceptionCheck() != 0) {
115      LOGE("*** Uncaught exception returned from Java call!\n");
116      env->ExceptionDescribe();
117      obj = NULL;
118    }
119  }
120  return obj;
121}
122
123static jobject android_emoji_EmojiFactory_newInstance(
124    JNIEnv* env, jobject clazz, jstring name) {
125  if (NULL == name) {
126    return NULL;
127  }
128  pthread_once(&g_once, InitializeCaller);
129  if (!lib_emoji_factory_is_ready) {
130    return NULL;
131  }
132
133  const jchar* jchars = env->GetStringChars(name, NULL);
134  jsize len = env->GetStringLength(name);
135  String8 str(String16(jchars, len));
136
137  EmojiFactory *factory = gCaller->TryCallGetImplementation(str.string());
138  // EmojiFactory *factory = EmojiFactory::GetImplementation(str.string());
139  if (NULL == factory) {
140    return NULL;
141  }
142  env->ReleaseStringChars(name, jchars);
143
144  return create_java_EmojiFactory(env, factory, name);
145}
146
147static jobject android_emoji_EmojiFactory_newAvailableInstance(
148    JNIEnv* env, jobject clazz) {
149  pthread_once(&g_once, InitializeCaller);
150  if (!lib_emoji_factory_is_ready) {
151    return NULL;
152  }
153
154  EmojiFactory *factory = gCaller->TryCallGetAvailableImplementation();
155  // EmojiFactory *factory = EmojiFactory::GetAvailableImplementation();
156  if (NULL == factory) {
157    return NULL;
158  }
159  String16 name_16(String8(factory->Name()));
160  jstring jname = env->NewString(name_16.string(), name_16.size());
161  if (NULL == jname) {
162    return NULL;
163  }
164
165  return create_java_EmojiFactory(env, factory, jname);
166}
167
168static jobject android_emoji_EmojiFactory_getBitmapFromAndroidPua(
169    JNIEnv* env, jobject clazz, jint nativeEmojiFactory, jint pua) {
170  EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
171
172  int size;
173  const char *bytes = factory->GetImageBinaryFromAndroidPua(pua, &size);
174  if (bytes == NULL) {
175    return NULL;
176  }
177
178  SkBitmap *bitmap = new SkBitmap;
179  if (!SkImageDecoder::DecodeMemory(bytes, size, bitmap)) {
180    LOGE("SkImageDecoder::DecodeMemory() failed.");
181    return NULL;
182  }
183
184  jobject obj = env->AllocObject(gBitmap_class);
185  if (obj) {
186    env->CallVoidMethod(obj, gBitmap_constructorMethodID,
187                        reinterpret_cast<jint>(bitmap), false, NULL);
188    if (env->ExceptionCheck() != 0) {
189      LOGE("*** Uncaught exception returned from Java call!\n");
190      env->ExceptionDescribe();
191      return NULL;
192    }
193  }
194
195  return obj;
196}
197
198static void android_emoji_EmojiFactory_destructor(
199    JNIEnv* env, jobject obj, jint nativeEmojiFactory) {
200  /*
201  // Must not delete this object!!
202  EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
203  delete factory;
204  */
205}
206
207static jint android_emoji_EmojiFactory_getAndroidPuaFromVendorSpecificSjis(
208    JNIEnv* env, jobject obj, jint nativeEmojiFactory, jchar sjis) {
209  EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
210  return factory->GetAndroidPuaFromVendorSpecificSjis(sjis);
211}
212
213static jint android_emoji_EmojiFactory_getVendorSpecificSjisFromAndroidPua(
214    JNIEnv* env, jobject obj, jint nativeEmojiFactory, jint pua) {
215  EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
216  return factory->GetVendorSpecificSjisFromAndroidPua(pua);
217}
218
219static jint android_emoji_EmojiFactory_getAndroidPuaFromVendorSpecificPua(
220    JNIEnv* env, jobject obj, jint nativeEmojiFactory, jint vsu) {
221  EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
222  return factory->GetAndroidPuaFromVendorSpecificPua(vsu);
223}
224
225static jint android_emoji_EmojiFactory_getVendorSpecificPuaFromAndroidPua(
226    JNIEnv* env, jobject obj, jint nativeEmojiFactory, jint pua) {
227  EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
228  return factory->GetVendorSpecificPuaFromAndroidPua(pua);
229}
230
231static jint android_emoji_EmojiFactory_getMaximumVendorSpecificPua(
232    JNIEnv* env, jobject obj, jint nativeEmojiFactory) {
233  EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
234  return factory->GetMaximumVendorSpecificPua();
235}
236
237static jint android_emoji_EmojiFactory_getMinimumVendorSpecificPua(
238    JNIEnv* env, jobject obj, jint nativeEmojiFactory) {
239  EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
240  return factory->GetMinimumVendorSpecificPua();
241}
242
243static jint android_emoji_EmojiFactory_getMaximumAndroidPua(
244    JNIEnv* env, jobject obj, jint nativeEmojiFactory) {
245  EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
246  return factory->GetMaximumAndroidPua();
247}
248
249static jint android_emoji_EmojiFactory_getMinimumAndroidPua(
250    JNIEnv* env, jobject obj, jint nativeEmojiFactory) {
251  EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
252  return factory->GetMinimumAndroidPua();
253}
254
255static JNINativeMethod gMethods[] = {
256  { "newInstance", "(Ljava/lang/String;)Landroid/emoji/EmojiFactory;",
257    (void*)android_emoji_EmojiFactory_newInstance},
258  { "newAvailableInstance", "()Landroid/emoji/EmojiFactory;",
259    (void*)android_emoji_EmojiFactory_newAvailableInstance},
260  { "nativeDestructor", "(I)V",
261    (void*)android_emoji_EmojiFactory_destructor},
262  { "nativeGetBitmapFromAndroidPua", "(II)Landroid/graphics/Bitmap;",
263    (void*)android_emoji_EmojiFactory_getBitmapFromAndroidPua},
264  { "nativeGetAndroidPuaFromVendorSpecificSjis", "(IC)I",
265    (void*)android_emoji_EmojiFactory_getAndroidPuaFromVendorSpecificSjis},
266  { "nativeGetVendorSpecificSjisFromAndroidPua", "(II)I",
267    (void*)android_emoji_EmojiFactory_getVendorSpecificSjisFromAndroidPua},
268  { "nativeGetAndroidPuaFromVendorSpecificPua", "(II)I",
269    (void*)android_emoji_EmojiFactory_getAndroidPuaFromVendorSpecificPua},
270  { "nativeGetVendorSpecificPuaFromAndroidPua", "(II)I",
271    (void*)android_emoji_EmojiFactory_getVendorSpecificPuaFromAndroidPua},
272  { "nativeGetMaximumVendorSpecificPua", "(I)I",
273    (void*)android_emoji_EmojiFactory_getMaximumVendorSpecificPua},
274  { "nativeGetMinimumVendorSpecificPua", "(I)I",
275    (void*)android_emoji_EmojiFactory_getMinimumVendorSpecificPua},
276  { "nativeGetMaximumAndroidPua", "(I)I",
277    (void*)android_emoji_EmojiFactory_getMaximumAndroidPua},
278  { "nativeGetMinimumAndroidPua", "(I)I",
279    (void*)android_emoji_EmojiFactory_getMinimumAndroidPua}
280};
281
282static jclass make_globalref(JNIEnv* env, const char classname[])
283{
284    jclass c = env->FindClass(classname);
285    SkASSERT(c);
286    return (jclass)env->NewGlobalRef(c);
287}
288
289static jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz,
290                                const char fieldname[], const char type[])
291{
292    jfieldID id = env->GetFieldID(clazz, fieldname, type);
293    SkASSERT(id);
294    return id;
295}
296
297int register_android_emoji_EmojiFactory(JNIEnv* env) {
298  gBitmap_class = make_globalref(env, "android/graphics/Bitmap");
299  gBitmap_constructorMethodID = env->GetMethodID(gBitmap_class, "<init>",
300                                                 "(IZ[B)V");
301  gEmojiFactory_class = make_globalref(env, "android/emoji/EmojiFactory");
302  gEmojiFactory_constructorMethodID = env->GetMethodID(
303      gEmojiFactory_class, "<init>", "(ILjava/lang/String;)V");
304  return jniRegisterNativeMethods(env, "android/emoji/EmojiFactory",
305                                  gMethods, NELEM(gMethods));
306}
307
308}  // namespace android
309