Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / xwalk / app / android / runtime_client / src / org / xwalk / app / runtime / extension / XWalkRuntimeExtensionManager.java
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 package org.xwalk.app.runtime.extension;
6
7 import android.app.Activity;
8 import android.content.Context;
9 import android.content.Intent;
10 import android.content.res.AssetManager;
11 import android.content.res.Resources;
12 import android.content.res.Resources.NotFoundException;
13 import android.util.Log;
14
15 import java.io.File;
16 import java.io.IOException;
17 import java.io.InputStream;
18 import java.lang.reflect.Constructor;
19 import java.lang.reflect.InvocationTargetException;
20 import java.lang.Class;
21 import java.util.HashMap;
22
23 import org.json.JSONArray;
24 import org.json.JSONException;
25 import org.json.JSONObject;
26
27 /**
28  * This internal class acts a manager to manage extensions.
29  */
30 public class XWalkRuntimeExtensionManager implements XWalkExtensionContextClient {
31     private final static String TAG = "XWalkExtensionManager";
32     private final static String EXTENSION_CONFIG_FILE = "extensions-config.json";
33
34     private final Context mContext;
35     private final Activity mActivity;
36
37     private final HashMap<String, XWalkRuntimeExtensionBridge> mExtensions = new HashMap<String, XWalkRuntimeExtensionBridge>();
38     // This variable is to set whether to load external extensions. The default is true.
39     private boolean mLoadExternalExtensions;
40
41     public XWalkRuntimeExtensionManager(Context context, Activity activity) {
42         mContext = context;
43         mActivity = activity;
44         mLoadExternalExtensions = true;
45     }
46
47     @Override
48     public void registerExtension(XWalkExtensionClient extension) {
49         if (mExtensions.get(extension.getExtensionName()) != null) {
50             Log.e(TAG, extension.getExtensionName() + "is already registered!");
51             return;
52         }
53
54         XWalkRuntimeExtensionBridge bridge = XWalkRuntimeExtensionBridgeFactory.createInstance(extension);
55         mExtensions.put(extension.getExtensionName(), bridge);
56     }
57
58     @Override
59     public void unregisterExtension(String name) {
60         XWalkRuntimeExtensionBridge bridge = mExtensions.get(name);
61         if (bridge != null) {
62             mExtensions.remove(name);
63             bridge.onDestroy();
64         }
65     }
66
67     @Override
68     public Context getContext() {
69         return mContext;
70     }
71
72     @Override
73     public Activity getActivity() {
74         return mActivity;
75     }
76
77     @Override
78     public void postMessage(XWalkExtensionClient extension, int instanceID, String message) {
79         XWalkRuntimeExtensionBridge bridge = mExtensions.get(extension.getExtensionName());
80         if (bridge != null) bridge.postMessage(instanceID, message);
81     }
82
83     public void broadcastMessage(XWalkExtensionClient extension, String message) {
84         XWalkRuntimeExtensionBridge bridge = mExtensions.get(extension.getExtensionName());
85         if (bridge != null) bridge.broadcastMessage(message);
86     }
87
88     public void onStart() {
89         for(XWalkRuntimeExtensionBridge extension: mExtensions.values()) {
90             extension.onStart();
91         }
92     }
93
94     public void onResume() {
95         for(XWalkRuntimeExtensionBridge extension: mExtensions.values()) {
96             extension.onResume();
97         }
98     }
99
100     public void onPause() {
101         for(XWalkRuntimeExtensionBridge extension: mExtensions.values()) {
102             extension.onPause();
103         }
104     }
105
106     public void onStop() {
107         for(XWalkRuntimeExtensionBridge extension: mExtensions.values()) {
108             extension.onStop();
109         }
110     }
111
112     public void onDestroy() {
113         for(XWalkRuntimeExtensionBridge extension: mExtensions.values()) {
114             extension.onDestroy();
115         }
116         mExtensions.clear();
117     }
118
119     public void onActivityResult(int requestCode, int resultCode, Intent data) {
120         for(XWalkRuntimeExtensionBridge extension: mExtensions.values()) {
121             extension.onActivityResult(requestCode, resultCode, data);
122         }
123     }
124
125     public void loadExtensions() {
126         loadExternalExtensions();
127     }
128
129     public void setAllowExternalExtensions(boolean load) {
130         mLoadExternalExtensions = load;
131     }
132
133     private void loadExternalExtensions() {
134         if (!mLoadExternalExtensions) return;
135
136         // Read extensions-config.json and create external extensions.
137         String configFileContent;
138         try {
139             configFileContent = getExtensionJSFileContent(mActivity, EXTENSION_CONFIG_FILE, false);
140         } catch (IOException e) {
141             Log.w(TAG, "Failed to read extensions-config.json");
142             return;
143         }
144
145         try {
146             JSONArray jsonFeatures = new JSONArray(configFileContent);
147             int extensionCount = jsonFeatures.length();
148             for (int i = 0; i < extensionCount; i++) {
149                 JSONObject jsonObject = jsonFeatures.getJSONObject(i);
150                 String name = jsonObject.getString("name");
151                 String className =  jsonObject.getString("class");
152                 String jsApiFile = jsonObject.getString("jsapi");
153
154                 // Load the content of the JavaScript file.
155                 String jsApi;
156                 try {
157                     jsApi = getExtensionJSFileContent(mActivity, jsApiFile, false);
158                 } catch (IOException e) {
159                     Log.w(TAG, "Failed to read the file " + jsApiFile);
160                     return;
161                 }
162
163                 if (name != null && className != null && jsApi != null) {
164                     createExternalExtension(name, className, jsApi, this);
165                 }
166             }
167         } catch (JSONException e) {
168             Log.w(TAG, "Failed to parse extensions-config.json");
169         }
170     }
171
172     private String getExtensionJSFileContent(Context context, String fileName, boolean fromRaw)
173             throws IOException {
174         String result = "";
175         InputStream inputStream = null;
176         try {
177             if (fromRaw) {
178                 // If fromRaw is true, Try to find js file in res/raw first.
179                 // And then try to get it from assets if failed.
180                 Resources resource = context.getResources();
181                 String resName = (new File(fileName).getName().split("\\."))[0];
182                 int resId = resource.getIdentifier(resName, "raw", context.getPackageName());
183                 if (resId > 0) {
184                     try {
185                         inputStream = resource.openRawResource(resId);
186                     } catch (NotFoundException e) {
187                         Log.w(TAG, "Inputstream failed to open for R.raw." + resName +
188                                    ", try to find it in assets");
189                     }
190                 }
191             }
192             if (inputStream == null) {
193                 AssetManager assetManager = context.getAssets();
194                 inputStream = assetManager.open(fileName);
195             }
196             int size = inputStream.available();
197             byte[] buffer = new byte[size];
198             inputStream.read(buffer);
199             result = new String(buffer);
200         } finally {
201             if (inputStream != null) {
202                 inputStream.close();
203             }
204         }
205         return result;
206     }
207
208     private void createExternalExtension(String name, String className, String jsApi,
209             XWalkExtensionContextClient extensionContext) {
210         Activity activity = extensionContext.getActivity();
211         try {
212             Class<?> clazz = activity.getClassLoader().loadClass(className);
213             Constructor<?> constructor = clazz.getConstructor(String.class,
214                     String.class, XWalkExtensionContextClient.class);
215             constructor.newInstance(name, jsApi, this);
216         } catch (ClassNotFoundException e) {
217             handleException(e);
218         } catch (IllegalAccessException e) {
219             handleException(e);
220         } catch (InstantiationException e) {
221             handleException(e);
222         } catch (InvocationTargetException e) {
223             handleException(e);
224         } catch (NoSuchMethodException e) {
225             handleException(e);
226         }
227     }
228
229     private static void handleException(Exception e) {
230         // TODO(yongsheng): Handle exceptions here.
231         Log.e(TAG, "Error in calling methods of external extensions. " + e.toString());
232     }
233 }