blob: 7beb98d9b405b9c88b9b6c85e931c15fd69f62ad [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);
Vivek Sekhardcf9d6b2014-12-01 15:08:37 -0800205 // Add the browser commandline options
206 BrowserConfig.getInstance(ctx).initCommandLineSwitches();
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700207 //Enable remote debugging by default
208 Engine.setWebContentsDebuggingEnabled(true);
209 mInitializationCompleted = true;
210 mLibraryLoaded = true;
211 BrowserSettings.getInstance().onEngineInitializationComplete();
212 }
213 if (mActivity != null && mNotifyActivity) {
214 mNotifyActivity = false;
215 postOnUiThread(new Runnable() {
216 @Override
217 public void run() {
218 mActivity.onEngineInitializationComplete();
219 mActivityReady = true;
220 processPendingEvents();
221 }
222 });
223 }
224
225 }
226
227 private void processPendingEvents() {
228 assert runningOnUiThread() : "Tried to initialize the engine on the wrong thread.";
229
230 if (mActivityStartPending) {
231 mActivityStartPending = false;
232 onActivityStart();
233 }
234 if (mPendingIntents != null) {
235 for (int i = 0; i < mPendingIntents.size(); i++) {
236 mActivity.handleOnNewIntent(mPendingIntents.get(i));
237 }
238 mPendingIntents = null;
239 }
240 if (mPendingActivityResults != null) {
241 for (int i = 0; i < mPendingActivityResults.size(); i++) {
242 ActivityResult result = mPendingActivityResults.get(i);
243 mActivity.handleOnActivityResult(result.requestCode, result.resultCode, result.data);
244 }
245 mPendingActivityResults = null;
246 }
247 if (mOnResumePending && !mActivityDestroyed) {
248 onActivityResume();
249 }
250 mOnResumePending = false;
251 }
252
253 public void onPreDraw() {
254 mFirstDrawCompleted = true;
255 if (mLibraryLoaded) {
256 completeInitialization();
257 }
258 }
259
260 public void initializeResourceExtractor(Context ctx) {
261 Engine.startExtractingResources(ctx);
262 }
263
264 public void onActivityPause() {
265 mOnResumePending = false;
266 if (mActivityReady) {
Vivek Sekhar2868b8d2014-12-03 17:22:50 -0800267 mActivity.handleOnPause();
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700268 }
269 }
270
Tarun Nainanib4a173f2015-01-05 09:23:08 -0800271 public void onActivityStop() {
272 mActivityStartPending = false;
273 if (mActivityReady) {
274 Engine.pauseTracing(mActivity.getApplicationContext());
275 mActivity.handleOnStop();
276 }
277 }
278
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700279 public void onActivityResume() {
280 if (mActivityReady) {
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700281 mActivity.handleOnResume();
282 return;
283 }
284 mOnResumePending = true;
285 }
286
287 public void onActivityStart() {
288 if (mActivityReady) {
Tarun Nainanib4a173f2015-01-05 09:23:08 -0800289 Engine.resumeTracing(mActivity.getApplicationContext());
290 mActivity.handleOnStart();
Kulanthaivel Palanichamy77942682014-10-28 11:52:06 -0700291 // TODO: We have no reliable mechanism to know when the app goes background.
292 //ChildProcessLauncher.onBroughtToForeground();
293 return;
294 }
295 mActivityStartPending = true;
296 }
297
298 public void onActivityResult(int requestCode, int resultCode, Intent data) {
299 if (mActivityReady) {
300 mActivity.handleOnActivityResult(requestCode, resultCode, data);
301 return;
302 }
303 if (mPendingActivityResults == null) {
304 mPendingActivityResults = new ArrayList<ActivityResult>(1);
305 }
306 mPendingActivityResults.add(new ActivityResult(requestCode, resultCode, data));
307 }
308
309 public void onNewIntent(Intent intent) {
310 if (mActivityReady) {
311 mActivity.handleOnNewIntent(intent);
312 return;
313 }
314
315 if (mPendingIntents == null) {
316 mPendingIntents = new ArrayList<Intent>(1);
317 }
318 mPendingIntents.add(intent);
319 }
320
321 public void onActivityDestroy() {
322 mActivityDestroyed = true;
323 }
324
325
326}