blob: 10cbc0dc85a7af4982d768d3040ae90ea43b2230 [file] [log] [blame]
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -07001/*
2 * Copyright (c) 2014 The Linux Foundation. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above
10 * copyright notice, this list of conditions and the following
11 * disclaimer in the documentation and/or other materials provided
12 * with the distribution.
13 * * Neither the name of The Linux Foundation nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 */
30
31package com.android.browser;
32
33import android.content.Context;
34import android.content.Intent;
35import android.os.AsyncTask;
36import android.os.Handler;
37import android.os.Looper;
38import android.util.Log;
39
40import org.codeaurora.swe.Engine;
41
42import java.util.ArrayList;
43import java.util.concurrent.CancellationException;
44import java.util.concurrent.ExecutionException;
45
46import com.google.common.annotations.VisibleForTesting;
47
48public class EngineInitializer {
49 private final static String LOGTAG = "EngineInitializer";
50
51 private BrowserActivity mActivity;
52
53 private boolean mNotifyActivity = false;
54 private boolean mActivityReady = false;
55 private boolean mActivityDestroyed = false;
56 private boolean mActivityStartPending = false;
57 private boolean mOnResumePending = false;
58
59 private boolean mFirstDrawCompleted = false;
60 private boolean mLibraryLoaded = false;
61 private boolean mInitializationCompleted = false;
62
63 private Handler mUiThreadHandler;
64
65 class ActivityResult
66 {
67 public Intent data;
68 public int requestCode;
69 public int resultCode;
70
71 public ActivityResult(int requestCode, int resultCode, Intent data)
72 {
73 this.requestCode = requestCode;
74 this.resultCode = resultCode;
75 this.data = data;
76 }
77 }
78 private ArrayList<ActivityResult> mPendingActivityResults = null;
79 private ArrayList<Intent> mPendingIntents = null;
80
81 private static EngineInitializer sEngineInitializer = null;
82 public static EngineInitializer getInstance() {
83 if (sEngineInitializer == null) {
84 sEngineInitializer = new EngineInitializer();
85 }
86 return sEngineInitializer;
87 }
88
89 private static long sDelayForTesting = 0;
90
91 @VisibleForTesting
92 public static void setDelayForTesting(long delay)
93 {
94 sDelayForTesting = delay;
95 }
96
97 private EngineInitializer() {
98 mUiThreadHandler = new Handler(Looper.getMainLooper());
99 }
100
101 @VisibleForTesting
102 public boolean isInitialized()
103 {
104 return mInitializationCompleted;
105 }
106
107 public boolean runningOnUiThread() {
108 return mUiThreadHandler.getLooper() == Looper.myLooper();
109 }
110
111 public void postOnUiThread(Runnable task) {
112 mUiThreadHandler.post(task);
113 }
114
115 private class InitializeTask extends AsyncTask<Void, Void, Boolean> {
116 public InitializeTask() {
117 }
118 @Override
119 protected Boolean doInBackground(Void... unused) {
120 try
121 {
122 // For testing.
123 if (sDelayForTesting > 0) {
124 Thread.sleep(sDelayForTesting);
125 }
126
127 Engine.loadNativeLibraries(mActivity.getApplicationContext());
128
129 Engine.warmUpChildProcess(mActivity.getApplicationContext());
130
131 return true;
132 }
133 catch (Exception e)
134 {
135 Log.e(LOGTAG, "Unable to load native library.", e);
136 }
137 return false;
138 }
139
140 @Override
141 protected void onPostExecute (Boolean result) {
142 mLibraryLoaded = true;
143 if (mFirstDrawCompleted) {
144 completeInitializationOnUiThread(mActivity.getApplicationContext());
145 }
146 }
147 }
148 private InitializeTask mInitializeTask = null;
149
150 public void initializeSync(Context ctx) {
151 assert runningOnUiThread() : "Tried to initialize the engine on the wrong thread.";
152
153 if (mInitializeTask != null) {
154 try {
155 // Wait for the InitializeTask to finish.
156 mInitializeTask.get();
157 } catch (CancellationException e1) {
158 Log.e(LOGTAG, "Native library load cancelled", e1);
159 } catch (ExecutionException e2) {
160 Log.e(LOGTAG, "Native library load failed", e2);
161 } catch (InterruptedException e3) {
162 Log.e(LOGTAG, "Native library load interrupted", e3);
163 }
164 }
165 completeInitializationOnUiThread(ctx);
166 }
167
168 private void reset(BrowserActivity newActivity) {
169 mActivity = newActivity;
170 mActivityStartPending = false;
171 mOnResumePending = false;
172 mNotifyActivity = true;
173 mActivityReady = false;
174 mPendingIntents = null;
175 mPendingActivityResults = null;
176 mFirstDrawCompleted = false;
177 mActivityDestroyed = false;
178 }
179
180 public void onActivityCreate(BrowserActivity activity) {
181 assert runningOnUiThread() : "Tried to initialize the engine on the wrong thread.";
182 reset(activity);
183 if (!mInitializationCompleted) {
184 Engine.initializeCommandLine(mActivity.getApplicationContext());
185 mInitializeTask = new InitializeTask();
186 mInitializeTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
187 }
188 }
189
190 private void completeInitialization() {
191 postOnUiThread(new Runnable() {
192 @Override
193 public void run() {
194 completeInitializationOnUiThread(mActivity.getApplicationContext());
195 }
196 });
197 }
198
199 private void completeInitializationOnUiThread(Context ctx) {
200 assert runningOnUiThread() : "Tried to initialize the engine on the wrong thread.";
201
202 if (!mInitializationCompleted) {
203 // TODO: Evaluate the benefit of async Engine.initialize()
204 Engine.initialize(ctx);
205 //Enable remote debugging by default
206 Engine.setWebContentsDebuggingEnabled(true);
207 mInitializationCompleted = true;
208 mLibraryLoaded = true;
209 BrowserSettings.getInstance().onEngineInitializationComplete();
210 }
211 if (mActivity != null && mNotifyActivity) {
212 mNotifyActivity = false;
213 postOnUiThread(new Runnable() {
214 @Override
215 public void run() {
216 mActivity.onEngineInitializationComplete();
217 mActivityReady = true;
218 processPendingEvents();
219 }
220 });
221 }
222
223 }
224
225 private void processPendingEvents() {
226 assert runningOnUiThread() : "Tried to initialize the engine on the wrong thread.";
227
228 if (mActivityStartPending) {
229 mActivityStartPending = false;
230 onActivityStart();
231 }
232 if (mPendingIntents != null) {
233 for (int i = 0; i < mPendingIntents.size(); i++) {
234 mActivity.handleOnNewIntent(mPendingIntents.get(i));
235 }
236 mPendingIntents = null;
237 }
238 if (mPendingActivityResults != null) {
239 for (int i = 0; i < mPendingActivityResults.size(); i++) {
240 ActivityResult result = mPendingActivityResults.get(i);
241 mActivity.handleOnActivityResult(result.requestCode, result.resultCode, result.data);
242 }
243 mPendingActivityResults = null;
244 }
245 if (mOnResumePending && !mActivityDestroyed) {
246 onActivityResume();
247 }
248 mOnResumePending = false;
249 }
250
251 public void onPreDraw() {
252 mFirstDrawCompleted = true;
253 if (mLibraryLoaded) {
254 completeInitialization();
255 }
256 }
257
258 public void initializeResourceExtractor(Context ctx) {
259 Engine.startExtractingResources(ctx);
260 }
261
262 public void onActivityPause() {
263 mOnResumePending = false;
264 if (mActivityReady) {
265 Engine.pauseTracing(mActivity.getApplicationContext());
266 }
267 }
268
269 public void onActivityResume() {
270 if (mActivityReady) {
271 Engine.resumeTracing(mActivity.getApplicationContext());
272 mActivity.handleOnResume();
273 return;
274 }
275 mOnResumePending = true;
276 }
277
278 public void onActivityStart() {
279 if (mActivityReady) {
280 // TODO: We have no reliable mechanism to know when the app goes background.
281 //ChildProcessLauncher.onBroughtToForeground();
282 return;
283 }
284 mActivityStartPending = true;
285 }
286
287 public void onActivityResult(int requestCode, int resultCode, Intent data) {
288 if (mActivityReady) {
289 mActivity.handleOnActivityResult(requestCode, resultCode, data);
290 return;
291 }
292 if (mPendingActivityResults == null) {
293 mPendingActivityResults = new ArrayList<ActivityResult>(1);
294 }
295 mPendingActivityResults.add(new ActivityResult(requestCode, resultCode, data));
296 }
297
298 public void onNewIntent(Intent intent) {
299 if (mActivityReady) {
300 mActivity.handleOnNewIntent(intent);
301 return;
302 }
303
304 if (mPendingIntents == null) {
305 mPendingIntents = new ArrayList<Intent>(1);
306 }
307 mPendingIntents.add(intent);
308 }
309
310 public void onActivityDestroy() {
311 mActivityDestroyed = true;
312 }
313
314
315}