Upstream version 10.38.208.0
[platform/framework/web/crosswalk.git] / src / xwalk / runtime / android / core_internal / src / org / xwalk / core / internal / XWalkViewDelegate.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.core.internal;
6
7 import java.io.InputStream;
8 import java.io.InputStreamReader;
9 import java.io.IOException;
10 import java.lang.StringBuilder;
11 import java.util.HashSet;
12 import java.util.Set;
13
14 import android.content.Context;
15 import android.content.res.AssetManager;
16 import android.content.res.Resources.NotFoundException;
17 import android.os.Build;
18 import android.util.Log;
19
20 import org.chromium.base.ApplicationStatusManager;
21 import org.chromium.base.CommandLine;
22 import org.chromium.base.JNINamespace;
23 import org.chromium.base.PathUtils;
24 import org.chromium.base.ThreadUtils;
25 import org.chromium.base.library_loader.LibraryLoader;
26 import org.chromium.base.library_loader.ProcessInitException;
27 import org.chromium.content.browser.BrowserStartupController;
28 import org.chromium.content.browser.DeviceUtils;
29 import org.chromium.content.browser.ResourceExtractor;
30 import org.chromium.content.browser.ResourceExtractor.ResourceIntercepter;
31 import org.chromium.net.NetworkChangeNotifier;
32
33 @JNINamespace("xwalk")
34 class XWalkViewDelegate {
35     private static boolean sInitialized = false;
36     private static boolean sRunningOnIA = true;
37     private static final String PRIVATE_DATA_DIRECTORY_SUFFIX = "xwalkcore";
38     private static final String[] MANDATORY_PAKS = {
39             "xwalk.pak",
40             "en-US.pak",
41             "icudtl.dat"
42     };
43     private static final String[] MANDATORY_LIBRARIES = {
44             "libxwalkcore.so"
45     };
46     private static final String TAG = "XWalkViewDelegate";
47     private static final String XWALK_RESOURCES_LIST_RES_NAME = "xwalk_resources_list";
48
49     private static final String COMMAND_LINE_FILE = "xwalk-command-line";
50
51     private static String[] readCommandLine(Context context) {
52         InputStreamReader reader = null;
53
54         try {
55             InputStream input =
56                     context.getAssets().open(COMMAND_LINE_FILE, AssetManager.ACCESS_BUFFER);
57             int length;
58             int size = 1024;
59             char[] buffer = new char[size];
60             StringBuilder builder = new StringBuilder();
61
62             reader = new InputStreamReader(input, "UTF-8");
63             while ((length = reader.read(buffer, 0, size)) != -1) {
64                 builder.append(buffer, 0, length);
65             }
66
67             return CommandLine.tokenizeQuotedAruments(
68                     builder.toString().toCharArray());
69         } catch (IOException e) {
70             return null;
71         } finally {
72             try {
73                 if (reader != null) reader.close();
74             } catch (IOException e) {
75                 Log.e(TAG, "Unable to close file reader.", e);
76             }
77         }
78     }
79
80     public static void init(XWalkViewInternal xwalkView) throws UnsatisfiedLinkError {
81         if (sInitialized) {
82             return;
83         }
84
85         // Initialize the ActivityStatus. This is needed and used by many internal
86         // features such as location provider to listen to activity status.
87         ApplicationStatusManager.init(xwalkView.getActivity().getApplication());
88
89         // Auto detect network connectivity state.
90         // setAutoDetectConnectivityState() need to be called before activity started.
91         NetworkChangeNotifier.init(xwalkView.getActivity());
92         NetworkChangeNotifier.setAutoDetectConnectivityState(true);
93
94         // We will miss activity onCreate() status in ApplicationStatusManager,
95         // informActivityStarted() will simulate these callbacks.
96         ApplicationStatusManager.informActivityStarted(xwalkView.getActivity());
97
98         final Context context = xwalkView.getViewContext();
99
100         // Last place to initialize CommandLine object. If you haven't initialize
101         // the CommandLine object before XWalkViewContent is created, here will create
102         // the object to guarantee the CommandLine object is not null and the
103         // consequent prodedure does not crash.
104         if (!CommandLine.isInitialized()) {
105             CommandLine.init(readCommandLine(context.getApplicationContext()));
106         }
107
108         // If context's applicationContext is not the same package with itself,
109         // It's a cross package invoking, load core library from library apk.
110         // Only load the native library from /data/data if the Android version is
111         // lower than 4.2. Android enables a system path /data/app-lib to store native
112         // libraries starting from 4.2 and load them automatically.
113         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1 &&
114                 !context.getApplicationContext().getPackageName().equals(context.getPackageName())) {
115             for (String library : MANDATORY_LIBRARIES) {
116                 System.load("/data/data/" + context.getPackageName() + "/lib/" + library);
117             }
118         }
119         loadLibrary(context);
120
121         if (sRunningOnIA && !nativeIsLibraryBuiltForIA()) {
122             throw new UnsatisfiedLinkError();
123         }
124
125         ResourceExtractor.setMandatoryPaksToExtract(MANDATORY_PAKS);
126         final int resourcesListResId = context.getResources().getIdentifier(
127                 XWALK_RESOURCES_LIST_RES_NAME, "array", context.getPackageName());
128         final AssetManager assets = context.getAssets();
129         if (!context.getPackageName().equals(context.getApplicationContext().getPackageName()) ||
130                 resourcesListResId != 0) {
131             // For shared mode, assets are in library package.
132             // For embedding API usage, assets are in res/raw.
133             ResourceExtractor.setResourceIntercepter(new ResourceIntercepter() {
134
135                 @Override
136                 public Set<String> getInterceptableResourceList() {
137                     Set<String> resourcesList = new HashSet<String>();
138                     if (!context.getPackageName().equals(
139                             context.getApplicationContext().getPackageName())) {
140                         try {
141                             for (String resource : assets.list("")) {
142                                 resourcesList.add(resource);
143                             }
144                         } catch (IOException e){}
145                     }
146                     if (resourcesListResId != 0) {
147                         try {
148                             String[] resources = context.getResources().getStringArray(resourcesListResId);
149                             for (String resource : resources) {
150                                 resourcesList.add(resource);
151                             }
152                         } catch (NotFoundException e) {
153                             Log.w(TAG, "R.array." + XWALK_RESOURCES_LIST_RES_NAME + " can't be found.");
154                         }
155                     }
156                     return resourcesList;
157                 }
158
159                 @Override
160                 public InputStream interceptLoadingForResource(String resource) {
161                     if (!context.getPackageName().equals(
162                             context.getApplicationContext().getPackageName())) {
163                         try {
164                             InputStream fromAsset = context.getAssets().open(resource);
165                             if (fromAsset != null) return fromAsset;
166                         } catch (IOException e) {
167                             Log.w(TAG, resource + " can't be found in assets.");
168                         }
169                     }
170
171                     if (resourcesListResId != 0) {
172                         String resourceName = resource.split("\\.")[0];
173                         int resId = context.getResources().getIdentifier(
174                                 resourceName, "raw", context.getPackageName());
175                         try {
176                             if (resId != 0) return context.getResources().openRawResource(resId);
177                         } catch (NotFoundException e) {
178                             Log.w(TAG, "R.raw." + resourceName + " can't be found.");
179                         }
180                     }
181
182                     return null;
183                 }
184             });
185         }
186         ResourceExtractor.setExtractImplicitLocaleForTesting(false);
187         // Use MixedContext to initialize the ResourceExtractor, as the pak file
188         // is in the library apk if in shared apk mode.
189         ResourceExtractor.get(context);
190
191         startBrowserProcess(context);
192         sInitialized = true;
193     }
194
195     private static void loadLibrary(Context context) {
196         PathUtils.setPrivateDataDirectorySuffix(PRIVATE_DATA_DIRECTORY_SUFFIX);
197         try {
198             LibraryLoader.loadNow(context, true);
199         } catch (ProcessInitException e) {
200             throw new RuntimeException("Cannot load Crosswalk Core", e);
201         }
202     }
203
204     private static void startBrowserProcess(final Context context) {
205         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
206             @Override
207             public void run() {
208                 try {
209                     LibraryLoader.ensureInitialized();
210                 } catch (ProcessInitException e) {
211                     throw new RuntimeException("Cannot initialize Crosswalk Core", e);
212                 }
213                 DeviceUtils.addDeviceSpecificUserAgentSwitch(context);
214                 CommandLine.getInstance().appendSwitchWithValue(
215                         XWalkSwitches.PROFILE_NAME,
216                         XWalkPreferencesInternal.getStringValue(XWalkPreferencesInternal.PROFILE_NAME));
217                 try {
218                     BrowserStartupController.get(context).startBrowserProcessesSync(
219                         true);
220                 } catch (ProcessInitException e) {
221                     throw new RuntimeException("Cannot initialize Crosswalk Core", e);
222                 }
223             }
224         });
225     }
226
227     public static boolean isRunningOnIA() {
228         return sRunningOnIA;
229     }
230
231     private static native boolean nativeIsLibraryBuiltForIA();
232
233     static {
234         sRunningOnIA = Build.CPU_ABI.equalsIgnoreCase("x86");
235     }
236 }