|
1 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*- |
|
2 * This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 package org.mozilla.gecko; |
|
7 |
|
8 import org.mozilla.gecko.mozglue.GeckoLoader; |
|
9 import org.mozilla.gecko.mozglue.RobocopTarget; |
|
10 import org.mozilla.gecko.util.GeckoEventListener; |
|
11 import org.mozilla.gecko.util.ThreadUtils; |
|
12 |
|
13 import org.json.JSONObject; |
|
14 |
|
15 import android.content.Context; |
|
16 import android.content.res.Configuration; |
|
17 import android.content.res.Resources; |
|
18 import android.os.Handler; |
|
19 import android.os.Looper; |
|
20 import android.os.SystemClock; |
|
21 import android.util.Log; |
|
22 |
|
23 import java.io.IOException; |
|
24 import java.util.Locale; |
|
25 |
|
26 public class GeckoThread extends Thread implements GeckoEventListener { |
|
27 private static final String LOGTAG = "GeckoThread"; |
|
28 |
|
29 @RobocopTarget |
|
30 public enum LaunchState { |
|
31 Launching, |
|
32 WaitForDebugger, |
|
33 Launched, |
|
34 GeckoRunning, |
|
35 GeckoExiting, |
|
36 GeckoExited |
|
37 }; |
|
38 |
|
39 private static LaunchState sLaunchState = LaunchState.Launching; |
|
40 |
|
41 private static GeckoThread sGeckoThread; |
|
42 |
|
43 private final String mArgs; |
|
44 private final String mAction; |
|
45 private final String mUri; |
|
46 |
|
47 public static boolean ensureInit() { |
|
48 ThreadUtils.assertOnUiThread(); |
|
49 if (isCreated()) |
|
50 return false; |
|
51 sGeckoThread = new GeckoThread(sArgs, sAction, sUri); |
|
52 return true; |
|
53 } |
|
54 |
|
55 public static String sArgs; |
|
56 public static String sAction; |
|
57 public static String sUri; |
|
58 |
|
59 public static void setArgs(String args) { |
|
60 sArgs = args; |
|
61 } |
|
62 |
|
63 public static void setAction(String action) { |
|
64 sAction = action; |
|
65 } |
|
66 |
|
67 public static void setUri(String uri) { |
|
68 sUri = uri; |
|
69 } |
|
70 |
|
71 GeckoThread(String args, String action, String uri) { |
|
72 mArgs = args; |
|
73 mAction = action; |
|
74 mUri = uri; |
|
75 setName("Gecko"); |
|
76 GeckoAppShell.getEventDispatcher().registerEventListener("Gecko:Ready", this); |
|
77 } |
|
78 |
|
79 public static boolean isCreated() { |
|
80 return sGeckoThread != null; |
|
81 } |
|
82 |
|
83 public static void createAndStart() { |
|
84 if (ensureInit()) |
|
85 sGeckoThread.start(); |
|
86 } |
|
87 |
|
88 private String initGeckoEnvironment() { |
|
89 // At some point while loading the gecko libs our default locale gets set |
|
90 // so just save it to locale here and reset it as default after the join |
|
91 Locale locale = Locale.getDefault(); |
|
92 |
|
93 if (locale.toString().equalsIgnoreCase("zh_hk")) { |
|
94 locale = Locale.TRADITIONAL_CHINESE; |
|
95 Locale.setDefault(locale); |
|
96 } |
|
97 |
|
98 Context context = GeckoAppShell.getContext(); |
|
99 String resourcePath = ""; |
|
100 Resources res = null; |
|
101 String[] pluginDirs = null; |
|
102 try { |
|
103 pluginDirs = GeckoAppShell.getPluginDirectories(); |
|
104 } catch (Exception e) { |
|
105 Log.w(LOGTAG, "Caught exception getting plugin dirs.", e); |
|
106 } |
|
107 |
|
108 resourcePath = context.getPackageResourcePath(); |
|
109 res = context.getResources(); |
|
110 GeckoLoader.setupGeckoEnvironment(context, pluginDirs, context.getFilesDir().getPath()); |
|
111 |
|
112 GeckoLoader.loadSQLiteLibs(context, resourcePath); |
|
113 GeckoLoader.loadNSSLibs(context, resourcePath); |
|
114 GeckoLoader.loadGeckoLibs(context, resourcePath); |
|
115 GeckoJavaSampler.setLibsLoaded(); |
|
116 |
|
117 Locale.setDefault(locale); |
|
118 |
|
119 Configuration config = res.getConfiguration(); |
|
120 config.locale = locale; |
|
121 res.updateConfiguration(config, res.getDisplayMetrics()); |
|
122 |
|
123 return resourcePath; |
|
124 } |
|
125 |
|
126 private String getTypeFromAction(String action) { |
|
127 if (action != null && action.startsWith(GeckoApp.ACTION_WEBAPP_PREFIX)) { |
|
128 return "-webapp"; |
|
129 } |
|
130 if (GeckoApp.ACTION_BOOKMARK.equals(action)) { |
|
131 return "-bookmark"; |
|
132 } |
|
133 return null; |
|
134 } |
|
135 |
|
136 private String addCustomProfileArg(String args) { |
|
137 String profile = ""; |
|
138 String guest = ""; |
|
139 if (GeckoAppShell.getGeckoInterface() != null) { |
|
140 if (GeckoAppShell.getGeckoInterface().getProfile().inGuestMode()) { |
|
141 try { |
|
142 profile = " -profile " + GeckoAppShell.getGeckoInterface().getProfile().getDir().getCanonicalPath(); |
|
143 } catch (IOException ioe) { Log.e(LOGTAG, "error getting guest profile path", ioe); } |
|
144 |
|
145 if (args == null || !args.contains(BrowserApp.GUEST_BROWSING_ARG)) { |
|
146 guest = " " + BrowserApp.GUEST_BROWSING_ARG; |
|
147 } |
|
148 } else if (!GeckoProfile.sIsUsingCustomProfile) { |
|
149 // If nothing was passed in in the intent, force Gecko to use the default profile for |
|
150 // for this activity |
|
151 profile = " -P " + GeckoAppShell.getGeckoInterface().getProfile().getName(); |
|
152 } |
|
153 } |
|
154 |
|
155 return (args != null ? args : "") + profile + guest; |
|
156 } |
|
157 |
|
158 @Override |
|
159 public void run() { |
|
160 Looper.prepare(); |
|
161 ThreadUtils.sGeckoThread = this; |
|
162 ThreadUtils.sGeckoHandler = new Handler(); |
|
163 ThreadUtils.sGeckoQueue = Looper.myQueue(); |
|
164 |
|
165 String path = initGeckoEnvironment(); |
|
166 |
|
167 Log.w(LOGTAG, "zerdatime " + SystemClock.uptimeMillis() + " - runGecko"); |
|
168 |
|
169 String args = addCustomProfileArg(mArgs); |
|
170 String type = getTypeFromAction(mAction); |
|
171 |
|
172 // and then fire us up |
|
173 Log.i(LOGTAG, "RunGecko - args = " + args); |
|
174 GeckoAppShell.runGecko(path, args, mUri, type); |
|
175 } |
|
176 |
|
177 private static Object sLock = new Object(); |
|
178 |
|
179 @Override |
|
180 public void handleMessage(String event, JSONObject message) { |
|
181 if ("Gecko:Ready".equals(event)) { |
|
182 GeckoAppShell.getEventDispatcher().unregisterEventListener(event, this); |
|
183 setLaunchState(LaunchState.GeckoRunning); |
|
184 GeckoAppShell.sendPendingEventsToGecko(); |
|
185 } |
|
186 } |
|
187 |
|
188 @RobocopTarget |
|
189 public static boolean checkLaunchState(LaunchState checkState) { |
|
190 synchronized (sLock) { |
|
191 return sLaunchState == checkState; |
|
192 } |
|
193 } |
|
194 |
|
195 static void setLaunchState(LaunchState setState) { |
|
196 synchronized (sLock) { |
|
197 sLaunchState = setState; |
|
198 } |
|
199 } |
|
200 |
|
201 /** |
|
202 * Set the launch state to <code>setState</code> and return true if the current launch |
|
203 * state is <code>checkState</code>; otherwise do nothing and return false. |
|
204 */ |
|
205 static boolean checkAndSetLaunchState(LaunchState checkState, LaunchState setState) { |
|
206 synchronized (sLock) { |
|
207 if (sLaunchState != checkState) |
|
208 return false; |
|
209 sLaunchState = setState; |
|
210 return true; |
|
211 } |
|
212 } |
|
213 } |