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