- add third_party src.
[platform/framework/web/crosswalk.git] / src / xwalk / extensions / common / android / xwalk_extension_android.cc
1 // Copyright (c) 2013 Intel Corporation. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "xwalk/extensions/common/android/xwalk_extension_android.h"
6
7 #include "base/android/jni_android.h"
8 #include "base/bind.h"
9 #include "base/logging.h"
10 #include "jni/XWalkExtensionAndroid_jni.h"
11 #include "xwalk/extensions/common/xwalk_extension.h"
12 #include "xwalk/runtime/browser/xwalk_browser_main_parts_android.h"
13 #include "xwalk/runtime/browser/xwalk_content_browser_client.h"
14
15 namespace xwalk {
16 namespace extensions {
17
18 XWalkExtensionAndroid::XWalkExtensionAndroid(JNIEnv* env, jobject obj,
19                                              jstring name, jstring js_api)
20     : XWalkExtension(),
21       java_ref_(env, obj),
22       next_instance_id_(1) {
23   const char *str = env->GetStringUTFChars(name, 0);
24   set_name(str);
25   env->ReleaseStringUTFChars(name, str);
26
27   str = env->GetStringUTFChars(js_api, 0);
28   set_javascript_api(str);
29   env->ReleaseStringUTFChars(js_api, str);
30 }
31
32 XWalkExtensionAndroid::~XWalkExtensionAndroid() {
33   // The |instances_| holds references to the instances created from this
34   // extension, but it doesn't own the object. The instance deletion is
35   // transferred to XWalkExtensionServer.
36   instances_.clear();
37 }
38
39 bool XWalkExtensionAndroid::is_valid() {
40   if (instances_.empty() || javascript_api().empty()) {
41     return false;
42   }
43
44   return true;
45 }
46
47 void XWalkExtensionAndroid::PostMessage(JNIEnv* env, jobject obj,
48                                        jint instance, jstring msg) {
49   if (!is_valid()) return;
50
51   InstanceMap::iterator it = instances_.find(instance);
52   if (it == instances_.end()) {
53     LOG(WARNING) << "Instance(" << instance << ") not found ";
54     return;
55   }
56
57   const char* str = env->GetStringUTFChars(msg, 0);
58   it->second->PostMessageWrapper(str);
59   env->ReleaseStringUTFChars(msg, str);
60 }
61
62 void XWalkExtensionAndroid::BroadcastMessage(JNIEnv* env, jobject obj,
63                                              jstring msg) {
64   if (!is_valid()) return;
65
66   const char* str = env->GetStringUTFChars(msg, 0);
67   for (InstanceMap::iterator it = instances_.begin();
68        it != instances_.end(); ++it) {
69     it->second->PostMessageWrapper(str);
70   }
71   env->ReleaseStringUTFChars(msg, str);
72 }
73
74 void XWalkExtensionAndroid::DestroyExtension(JNIEnv* env, jobject obj) {
75   // Since XWalkExtensionServer owns this native object, and it won't be deleted
76   // at this point even if the corresponding Java-side object is destroyed.
77   // Instead, we only reset the java reference to the Java-side object and id
78   // counter. See comments in xwalk_extension_android.h.
79   java_ref_.reset();
80   next_instance_id_ = 1;
81 }
82
83 XWalkExtensionInstance* XWalkExtensionAndroid::CreateInstance() {
84   JNIEnv* env = base::android::AttachCurrentThread();
85   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
86   if (obj.is_null()) {
87     return NULL;
88   }
89
90   XWalkExtensionAndroidInstance* instance =
91       new XWalkExtensionAndroidInstance(this, java_ref_, next_instance_id_);
92   instances_[next_instance_id_] = instance;
93
94   next_instance_id_++;
95
96   // Here we return the raw pointer to its caller XWalkExtensionServer. Since
97   // XWalkExtensionServer has a map to maintain all instances created, the
98   // ownership is also transferred to XWalkExtensionServer so that the instance
99   // should be deleted by XWalkExtensionServer.
100   return instance;
101 }
102
103 void XWalkExtensionAndroid::RemoveInstance(int instance) {
104   JNIEnv* env = base::android::AttachCurrentThread();
105   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
106   if (obj.is_null()) {
107     return;
108   }
109
110   InstanceMap::iterator it = instances_.find(instance);
111   if (it == instances_.end()) {
112     LOG(WARNING) << "Instance(" << instance << ") not found ";
113     return;
114   }
115
116   instances_.erase(instance);
117 }
118
119 void XWalkExtensionAndroid::BindToJavaObject(JNIEnv* env, jobject obj) {
120   JavaObjectWeakGlobalRef ref(env, obj);
121   java_ref_ = ref;
122 }
123
124 XWalkExtensionAndroidInstance::XWalkExtensionAndroidInstance(
125     XWalkExtensionAndroid* extension,
126     const JavaObjectWeakGlobalRef& java_ref,
127     int id)
128     : extension_(extension),
129       java_ref_(java_ref),
130       id_(id) {
131 }
132
133 XWalkExtensionAndroidInstance::~XWalkExtensionAndroidInstance() {
134   extension_->RemoveInstance(id_);
135 }
136
137 void XWalkExtensionAndroidInstance::HandleMessage(
138     scoped_ptr<base::Value> msg) {
139   std::string value;
140
141   if (!msg->GetAsString(&value)) {
142     return;
143   }
144
145   JNIEnv* env = base::android::AttachCurrentThread();
146   jstring buffer = env->NewStringUTF(value.c_str());
147   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
148   if (obj.is_null()) {
149     LOG(ERROR) << "No valid Java object is referenced for message routing";
150     return;
151   }
152
153   Java_XWalkExtensionAndroid_handleMessage(env, obj.obj(), getID(), buffer);
154 }
155
156 void XWalkExtensionAndroidInstance::HandleSyncMessage(
157     scoped_ptr<base::Value> msg) {
158   base::StringValue* ret_val = base::Value::CreateStringValue("");
159
160   std::string value;
161   if (!msg->GetAsString(&value)) {
162     SendSyncReplyToJS(scoped_ptr<base::Value>(ret_val));
163     return;
164   }
165
166   JNIEnv* env = base::android::AttachCurrentThread();
167   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
168   if (obj.is_null()) {
169     LOG(ERROR) << "No valid Java object is referenced for sync message routing";
170     SendSyncReplyToJS(scoped_ptr<base::Value>(ret_val));
171     return;
172   }
173
174   jstring buffer = env->NewStringUTF(value.c_str());
175   ScopedJavaLocalRef<jstring> ret =
176       Java_XWalkExtensionAndroid_handleSyncMessage(
177               env, obj.obj(), getID(), buffer);
178
179   const char *str = env->GetStringUTFChars(ret.obj(), 0);
180   ret_val = base::Value::CreateStringValue(str);
181   env->ReleaseStringUTFChars(ret.obj(), str);
182
183   SendSyncReplyToJS(scoped_ptr<base::Value>(ret_val));
184 }
185
186 static jint GetOrCreateExtension(JNIEnv* env, jobject obj,
187                                  jstring name, jstring js_api) {
188   xwalk::XWalkBrowserMainPartsAndroid* main_parts =
189       ToAndroidMainParts(XWalkContentBrowserClient::Get()->main_parts());
190
191   const char *str = env->GetStringUTFChars(name, 0);
192   XWalkExtension* extension = main_parts->LookupExtension(str);
193   env->ReleaseStringUTFChars(name, str);
194
195   // Create a new extension object if no existing one is found.
196   if (!extension) {
197     extension = new XWalkExtensionAndroid(env, obj, name, js_api);
198     main_parts->RegisterExtension(scoped_ptr<XWalkExtension>(extension));
199   } else {
200     static_cast<XWalkExtensionAndroid*>(extension)->BindToJavaObject(env, obj);
201   }
202
203   return reinterpret_cast<jint>(extension);
204 }
205
206 bool RegisterXWalkExtensionAndroid(JNIEnv* env) {
207   return RegisterNativesImpl(env) >= 0;
208 }
209
210 }  // namespace extensions
211 }  // namespace xwalk