diff -r 000000000000 -r 6474c204b198 mobile/android/base/GeckoThread.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mobile/android/base/GeckoThread.java Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,213 @@ +/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.gecko; + +import org.mozilla.gecko.mozglue.GeckoLoader; +import org.mozilla.gecko.mozglue.RobocopTarget; +import org.mozilla.gecko.util.GeckoEventListener; +import org.mozilla.gecko.util.ThreadUtils; + +import org.json.JSONObject; + +import android.content.Context; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.os.Handler; +import android.os.Looper; +import android.os.SystemClock; +import android.util.Log; + +import java.io.IOException; +import java.util.Locale; + +public class GeckoThread extends Thread implements GeckoEventListener { + private static final String LOGTAG = "GeckoThread"; + + @RobocopTarget + public enum LaunchState { + Launching, + WaitForDebugger, + Launched, + GeckoRunning, + GeckoExiting, + GeckoExited + }; + + private static LaunchState sLaunchState = LaunchState.Launching; + + private static GeckoThread sGeckoThread; + + private final String mArgs; + private final String mAction; + private final String mUri; + + public static boolean ensureInit() { + ThreadUtils.assertOnUiThread(); + if (isCreated()) + return false; + sGeckoThread = new GeckoThread(sArgs, sAction, sUri); + return true; + } + + public static String sArgs; + public static String sAction; + public static String sUri; + + public static void setArgs(String args) { + sArgs = args; + } + + public static void setAction(String action) { + sAction = action; + } + + public static void setUri(String uri) { + sUri = uri; + } + + GeckoThread(String args, String action, String uri) { + mArgs = args; + mAction = action; + mUri = uri; + setName("Gecko"); + GeckoAppShell.getEventDispatcher().registerEventListener("Gecko:Ready", this); + } + + public static boolean isCreated() { + return sGeckoThread != null; + } + + public static void createAndStart() { + if (ensureInit()) + sGeckoThread.start(); + } + + private String initGeckoEnvironment() { + // At some point while loading the gecko libs our default locale gets set + // so just save it to locale here and reset it as default after the join + Locale locale = Locale.getDefault(); + + if (locale.toString().equalsIgnoreCase("zh_hk")) { + locale = Locale.TRADITIONAL_CHINESE; + Locale.setDefault(locale); + } + + Context context = GeckoAppShell.getContext(); + String resourcePath = ""; + Resources res = null; + String[] pluginDirs = null; + try { + pluginDirs = GeckoAppShell.getPluginDirectories(); + } catch (Exception e) { + Log.w(LOGTAG, "Caught exception getting plugin dirs.", e); + } + + resourcePath = context.getPackageResourcePath(); + res = context.getResources(); + GeckoLoader.setupGeckoEnvironment(context, pluginDirs, context.getFilesDir().getPath()); + + GeckoLoader.loadSQLiteLibs(context, resourcePath); + GeckoLoader.loadNSSLibs(context, resourcePath); + GeckoLoader.loadGeckoLibs(context, resourcePath); + GeckoJavaSampler.setLibsLoaded(); + + Locale.setDefault(locale); + + Configuration config = res.getConfiguration(); + config.locale = locale; + res.updateConfiguration(config, res.getDisplayMetrics()); + + return resourcePath; + } + + private String getTypeFromAction(String action) { + if (action != null && action.startsWith(GeckoApp.ACTION_WEBAPP_PREFIX)) { + return "-webapp"; + } + if (GeckoApp.ACTION_BOOKMARK.equals(action)) { + return "-bookmark"; + } + return null; + } + + private String addCustomProfileArg(String args) { + String profile = ""; + String guest = ""; + if (GeckoAppShell.getGeckoInterface() != null) { + if (GeckoAppShell.getGeckoInterface().getProfile().inGuestMode()) { + try { + profile = " -profile " + GeckoAppShell.getGeckoInterface().getProfile().getDir().getCanonicalPath(); + } catch (IOException ioe) { Log.e(LOGTAG, "error getting guest profile path", ioe); } + + if (args == null || !args.contains(BrowserApp.GUEST_BROWSING_ARG)) { + guest = " " + BrowserApp.GUEST_BROWSING_ARG; + } + } else if (!GeckoProfile.sIsUsingCustomProfile) { + // If nothing was passed in in the intent, force Gecko to use the default profile for + // for this activity + profile = " -P " + GeckoAppShell.getGeckoInterface().getProfile().getName(); + } + } + + return (args != null ? args : "") + profile + guest; + } + + @Override + public void run() { + Looper.prepare(); + ThreadUtils.sGeckoThread = this; + ThreadUtils.sGeckoHandler = new Handler(); + ThreadUtils.sGeckoQueue = Looper.myQueue(); + + String path = initGeckoEnvironment(); + + Log.w(LOGTAG, "zerdatime " + SystemClock.uptimeMillis() + " - runGecko"); + + String args = addCustomProfileArg(mArgs); + String type = getTypeFromAction(mAction); + + // and then fire us up + Log.i(LOGTAG, "RunGecko - args = " + args); + GeckoAppShell.runGecko(path, args, mUri, type); + } + + private static Object sLock = new Object(); + + @Override + public void handleMessage(String event, JSONObject message) { + if ("Gecko:Ready".equals(event)) { + GeckoAppShell.getEventDispatcher().unregisterEventListener(event, this); + setLaunchState(LaunchState.GeckoRunning); + GeckoAppShell.sendPendingEventsToGecko(); + } + } + + @RobocopTarget + public static boolean checkLaunchState(LaunchState checkState) { + synchronized (sLock) { + return sLaunchState == checkState; + } + } + + static void setLaunchState(LaunchState setState) { + synchronized (sLock) { + sLaunchState = setState; + } + } + + /** + * Set the launch state to setState and return true if the current launch + * state is checkState; otherwise do nothing and return false. + */ + static boolean checkAndSetLaunchState(LaunchState checkState, LaunchState setState) { + synchronized (sLock) { + if (sLaunchState != checkState) + return false; + sLaunchState = setState; + return true; + } + } +}