mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 564327 - Add Java wrapper in embedding/android [1/2]. patch by vlad, blassey, alexp, and me. r=dougt,ted
--HG-- extra : rebase_source : 94cd881a5af774626f1bc557c6f99850c10283df
This commit is contained in:
parent
c13e866236
commit
e2dedd3ec8
59
configure.in
59
configure.in
@ -6077,20 +6077,38 @@ MOZ_ARG_ENABLE_BOOL(javaxpcom,
|
||||
MOZ_JAVAXPCOM=1,
|
||||
MOZ_JAVAXPCOM= )
|
||||
|
||||
if test -n "${MOZ_JAVAXPCOM}"; then
|
||||
case "$host_os" in
|
||||
cygwin*|msvc*|mks*)
|
||||
if test -n "$JAVA_HOME"; then
|
||||
JAVA_HOME=`cygpath -u \`cygpath -m -s "$JAVA_HOME"\``
|
||||
fi
|
||||
;;
|
||||
*mingw*)
|
||||
if test -n "$JAVA_HOME"; then
|
||||
JAVA_HOME=`cd "$JAVA_HOME" && pwd`
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
case "$host_os" in
|
||||
cygwin*|msvc*|mks*)
|
||||
if test -n "$JAVA_HOME"; then
|
||||
JAVA_HOME=`cygpath -u \`cygpath -m -s "$JAVA_HOME"\``
|
||||
fi
|
||||
;;
|
||||
*mingw*)
|
||||
if test -n "$JAVA_HOME"; then
|
||||
JAVA_HOME=`cd "$JAVA_HOME" && pwd`
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
if test -n "${JAVA_BIN_PATH}"; then
|
||||
dnl Look for javac and jar in the specified path.
|
||||
JAVA_PATH="$JAVA_BIN_PATH"
|
||||
else
|
||||
dnl No path specified, so look for javac and jar in $JAVA_HOME & $PATH.
|
||||
JAVA_PATH="$JAVA_HOME/bin:$PATH"
|
||||
fi
|
||||
|
||||
MOZ_PATH_PROG(JAVA, java, :, [$JAVA_PATH])
|
||||
MOZ_PATH_PROG(JAVAC, javac, :, [$JAVA_PATH])
|
||||
MOZ_PATH_PROG(JAR, jar, :, [$JAVA_PATH])
|
||||
|
||||
if test -n "${JAVA_BIN_PATH}" || test "$OS_TARGET" = Android; then
|
||||
if test -z "$JAVA" || test "$JAVA" = ":" || test -z "$JAVAC" || test "$JAVAC" = ":" || test -z "$JAR" || test "$JAR" = ":"; then
|
||||
AC_MSG_ERROR([The programs java, javac and jar were not found. Set \$JAVA_HOME to your java sdk directory or use --with-java-bin-path={java-bin-dir}])
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -n "${MOZ_JAVAXPCOM}"; then
|
||||
if test -n "${JAVA_INCLUDE_PATH}"; then
|
||||
dnl Make sure jni.h exists in the given include path.
|
||||
if test ! -f "$JAVA_INCLUDE_PATH/jni.h"; then
|
||||
@ -6111,21 +6129,6 @@ if test -n "${MOZ_JAVAXPCOM}"; then
|
||||
AC_MSG_ERROR([The header jni.h was not found. Set \$JAVA_HOME to your java sdk directory, use --with-java-bin-path={java-bin-dir}, or reconfigure with --disable-javaxpcom.])
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -n "${JAVA_BIN_PATH}"; then
|
||||
dnl Look for javac and jar in the specified path.
|
||||
JAVA_PATH="$JAVA_BIN_PATH"
|
||||
else
|
||||
dnl No path specified, so look for javac and jar in $JAVA_HOME & $PATH.
|
||||
JAVA_PATH="$JAVA_HOME/bin:$PATH"
|
||||
fi
|
||||
|
||||
MOZ_PATH_PROG(JAVA, java, :, [$JAVA_PATH])
|
||||
MOZ_PATH_PROG(JAVAC, javac, :, [$JAVA_PATH])
|
||||
MOZ_PATH_PROG(JAR, jar, :, [$JAVA_PATH])
|
||||
if test -z "$JAVA" || test "$JAVA" = ":" || test -z "$JAVAC" || test "$JAVAC" = ":" || test -z "$JAR" || test "$JAR" = ":"; then
|
||||
AC_MSG_ERROR([The programs java, javac and jar were not found. Set \$JAVA_HOME to your java sdk directory, use --with-java-bin-path={java-bin-dir}, or reconfigure with --disable-javaxpcom.])
|
||||
fi
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
|
@ -52,4 +52,8 @@ XPCSHELL_TESTS = tests/unit
|
||||
DIRS += test
|
||||
endif
|
||||
|
||||
ifeq ($(OS_TARGET),Android)
|
||||
TOOL_DIRS = android
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
35
embedding/android/AndroidManifest.xml.in
Normal file
35
embedding/android/AndroidManifest.xml.in
Normal file
@ -0,0 +1,35 @@
|
||||
#filter substitution
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.mozilla.@MOZ_APP_NAME@"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.9.3">
|
||||
<uses-sdk android:minSdkVersion="5"
|
||||
android:targetSdkVersion="5"/>
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
|
||||
<application android:label="@MOZ_APP_DISPLAYNAME@"
|
||||
android:icon="@drawable/icon">
|
||||
<activity android:name="App"
|
||||
android:label="@MOZ_APP_DISPLAYNAME@"
|
||||
android:configChanges="keyboard|keyboardHidden|orientation|mcc|mnc"
|
||||
android:windowSoftInputMode="stateUnspecified|adjustResize">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="org.mozilla.gecko.DEBUG" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<receiver android:enabled="true" android:name="Restarter">
|
||||
<intent-filter>
|
||||
<action android:name="org.mozilla.gecko.restart@MOZ_APP_NAME@" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
</application>
|
||||
</manifest>
|
48
embedding/android/App.java.in
Normal file
48
embedding/android/App.java.in
Normal file
@ -0,0 +1,48 @@
|
||||
/* -*- Mode: Java; tab-width: 20; indent-tabs-mode: nil; -*-
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Android code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Brad Lassey <blassey@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#filter substitution
|
||||
package org.mozilla.@MOZ_APP_NAME@;
|
||||
|
||||
import org.mozilla.gecko.GeckoApp;
|
||||
|
||||
public class App extends GeckoApp {
|
||||
public String getAppName() {
|
||||
return "@MOZ_APP_NAME@";
|
||||
}
|
||||
};
|
||||
|
366
embedding/android/GeckoApp.java
Normal file
366
embedding/android/GeckoApp.java
Normal file
@ -0,0 +1,366 @@
|
||||
/* -*- Mode: Java; tab-width: 20; indent-tabs-mode: nil; -*-
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Android code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009-2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Vladimir Vukicevic <vladimir@pobox.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
package org.mozilla.gecko;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.zip.*;
|
||||
import java.nio.*;
|
||||
|
||||
import android.os.*;
|
||||
import android.app.*;
|
||||
import android.text.*;
|
||||
import android.view.*;
|
||||
import android.view.inputmethod.*;
|
||||
import android.content.*;
|
||||
import android.graphics.*;
|
||||
import android.widget.*;
|
||||
import android.hardware.*;
|
||||
|
||||
import android.util.*;
|
||||
|
||||
abstract public class GeckoApp
|
||||
extends Activity
|
||||
{
|
||||
public static FrameLayout mainLayout;
|
||||
public static GeckoSurfaceView surfaceView;
|
||||
public static GeckoApp mAppContext;
|
||||
|
||||
public static boolean useSoftwareDrawing;
|
||||
|
||||
void launch()
|
||||
{
|
||||
// unpack files in the components directory
|
||||
unpackComponents();
|
||||
// and then fire us up
|
||||
Intent i = getIntent();
|
||||
String env = i.getStringExtra("env0");
|
||||
Log.i("GeckoApp", "env0: "+ env);
|
||||
for (int c = 1; env != null; c++) {
|
||||
GeckoAppShell.putenv(env);
|
||||
env = i.getStringExtra("env" + c);
|
||||
Log.i("GeckoApp", "env"+ c +": "+ env);
|
||||
}
|
||||
GeckoAppShell.runGecko(getApplication().getPackageResourcePath(),
|
||||
i.getStringExtra("args"),
|
||||
i.getDataString());
|
||||
}
|
||||
|
||||
/** Called when the activity is first created. */
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
mAppContext = this;
|
||||
|
||||
// hide our window's title, we don't want it
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
|
||||
surfaceView = new GeckoSurfaceView(this);
|
||||
|
||||
mainLayout = new FrameLayout(this);
|
||||
mainLayout.addView(surfaceView,
|
||||
new FrameLayout.LayoutParams(FrameLayout.LayoutParams.FILL_PARENT,
|
||||
FrameLayout.LayoutParams.FILL_PARENT));
|
||||
|
||||
boolean useLaunchButton = false;
|
||||
|
||||
String intentAction = getIntent().getAction();
|
||||
if (intentAction != null && intentAction.equals("org.mozilla.gecko.DEBUG"))
|
||||
useLaunchButton = true;
|
||||
|
||||
setContentView(mainLayout,
|
||||
new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
|
||||
ViewGroup.LayoutParams.FILL_PARENT));
|
||||
|
||||
useSoftwareDrawing = true; //isInEmulator() == 1;
|
||||
|
||||
if (!GeckoAppShell.sGeckoRunning) {
|
||||
// Load our JNI libs; we need to do this before launch() because
|
||||
// setInitialSize will be called even before Gecko is actually up
|
||||
// and running.
|
||||
GeckoAppShell.loadGeckoLibs();
|
||||
|
||||
if (useLaunchButton) {
|
||||
final Button b = new Button(this);
|
||||
b.setText("Launch");
|
||||
b.setOnClickListener(new Button.OnClickListener() {
|
||||
public void onClick (View v) {
|
||||
// hide the button so we can't be launched again
|
||||
mainLayout.removeView(b);
|
||||
launch();
|
||||
}
|
||||
});
|
||||
mainLayout.addView(b, 300, 200);
|
||||
} else {
|
||||
launch();
|
||||
}
|
||||
}
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause()
|
||||
{
|
||||
// The user is navigating away from this activity, but nothing
|
||||
// has come to the foreground yet; for Gecko, we may want to
|
||||
// stop repainting, for example.
|
||||
|
||||
// Whatever we do here should be fast, because we're blocking
|
||||
// the next activity from showing up until we finish.
|
||||
|
||||
// onPause will be followed by either onResume or onStop.
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume()
|
||||
{
|
||||
// After an onPause, the activity is back in the foreground.
|
||||
// Undo whatever we did in onPause.
|
||||
super.onResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop()
|
||||
{
|
||||
// We're about to be stopped, potentially in preparation for
|
||||
// being destroyed. We're killable after this point -- as I
|
||||
// understand it, in extreme cases the process can be terminated
|
||||
// without going through onDestroy.
|
||||
//
|
||||
// We might also get an onRestart after this; not sure what
|
||||
// that would mean for Gecko if we were to kill it here.
|
||||
// Instead, what we should do here is save prefs, session,
|
||||
// etc., and generally mark the profile as 'clean', and then
|
||||
// dirty it again if we get an onResume.
|
||||
|
||||
// XXX do the above.
|
||||
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy()
|
||||
{
|
||||
// Tell Gecko to shutting down; we'll end up calling System.exit()
|
||||
// in onXreExit.
|
||||
GeckoAppShell.sendEventToGecko(new GeckoEvent(GeckoEvent.ACTIVITY_STOPPING));
|
||||
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(android.content.res.Configuration newConfig)
|
||||
{
|
||||
// nothing, just ignore
|
||||
super.onConfigurationChanged(newConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLowMemory()
|
||||
{
|
||||
// XXX TODO
|
||||
super.onLowMemory();
|
||||
}
|
||||
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
GeckoAppShell.sendEventToGecko(new GeckoEvent(event));
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean onKeyUp(int keyCode, KeyEvent event) {
|
||||
GeckoAppShell.sendEventToGecko(new GeckoEvent(event));
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
|
||||
GeckoAppShell.sendEventToGecko(new GeckoEvent(event));
|
||||
return true;
|
||||
}
|
||||
|
||||
abstract public String getAppName();
|
||||
|
||||
protected void unpackComponents()
|
||||
{
|
||||
ZipFile zip;
|
||||
InputStream listStream;
|
||||
|
||||
try {
|
||||
File componentsDir = new File("/data/data/org.mozilla." + getAppName() +"/components");
|
||||
componentsDir.mkdir();
|
||||
zip = new ZipFile(getApplication().getPackageResourcePath());
|
||||
|
||||
ZipEntry componentsList = zip.getEntry("components/components.list");
|
||||
if (componentsList == null) {
|
||||
Log.i("GeckoAppJava", "Can't find components.list !");
|
||||
return;
|
||||
}
|
||||
|
||||
listStream = new BufferedInputStream(zip.getInputStream(componentsList));
|
||||
} catch (Exception e) {
|
||||
Log.i("GeckoAppJava", e.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
byte[] buf = new byte[8192];
|
||||
|
||||
StreamTokenizer tkn = new StreamTokenizer(new InputStreamReader(listStream));
|
||||
String line = "components/";
|
||||
int status;
|
||||
tkn.eolIsSignificant(true);
|
||||
do {
|
||||
try {
|
||||
status = tkn.nextToken();
|
||||
} catch (IOException e) {
|
||||
Log.i("GeckoAppJava", e.toString());
|
||||
return;
|
||||
}
|
||||
switch (status) {
|
||||
case StreamTokenizer.TT_WORD:
|
||||
line += tkn.sval;
|
||||
break;
|
||||
case StreamTokenizer.TT_NUMBER:
|
||||
line += tkn.nval;
|
||||
break;
|
||||
case StreamTokenizer.TT_EOF:
|
||||
case StreamTokenizer.TT_EOL:
|
||||
if (!line.endsWith(".js"))
|
||||
unpackFile(zip, buf, null, line);
|
||||
line = "components/";
|
||||
break;
|
||||
}
|
||||
} while (status != StreamTokenizer.TT_EOF);
|
||||
|
||||
unpackFile(zip, buf, null, "application.ini");
|
||||
}
|
||||
|
||||
private void unpackFile(ZipFile zip, byte[] buf, ZipEntry fileEntry, String name)
|
||||
{
|
||||
if (fileEntry == null)
|
||||
fileEntry = zip.getEntry(name);
|
||||
if (fileEntry == null) {
|
||||
Log.i("GeckoAppJava", "Can't find " + name + " in " + zip.getName());
|
||||
return;
|
||||
}
|
||||
|
||||
File outFile = new File("/data/data/org.mozilla." + getAppName() + "/" + name);
|
||||
if (outFile.exists() &&
|
||||
outFile.lastModified() >= fileEntry.getTime() &&
|
||||
outFile.length() == fileEntry.getSize())
|
||||
return;
|
||||
|
||||
try {
|
||||
File dir = outFile.getParentFile();
|
||||
if (!outFile.exists())
|
||||
dir.mkdirs();
|
||||
} catch (Exception e) {
|
||||
Log.i("GeckoAppJava", e.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
InputStream fileStream;
|
||||
try {
|
||||
fileStream = zip.getInputStream(fileEntry);
|
||||
} catch (Exception e) {
|
||||
Log.i("GeckoAppJava", e.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
OutputStream outStream;
|
||||
try {
|
||||
outStream = new FileOutputStream(outFile);
|
||||
|
||||
while (fileStream.available() > 0) {
|
||||
int read = fileStream.read(buf, 0, buf.length);
|
||||
outStream.write(buf, 0, read);
|
||||
}
|
||||
|
||||
fileStream.close();
|
||||
outStream.close();
|
||||
} catch (Exception e) {
|
||||
Log.i("GeckoAppJava", e.toString());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public String getEnvString() {
|
||||
Map<String,String> envMap = System.getenv();
|
||||
Set<Map.Entry<String,String>> envSet = envMap.entrySet();
|
||||
Iterator<Map.Entry<String,String>> envIter = envSet.iterator();
|
||||
StringBuffer envstr = new StringBuffer();
|
||||
int c = 0;
|
||||
while (envIter.hasNext()) {
|
||||
Map.Entry<String,String> entry = envIter.next();
|
||||
// No need to pass env vars that we know the system provides
|
||||
// Unnecessary vars need to be trimmed since amount of data
|
||||
// we can pass this way is limited
|
||||
if (!entry.getKey().equals("BOOTCLASSPATH") &&
|
||||
!entry.getKey().equals("ANDROID_SOCKET_zygote") &&
|
||||
!entry.getKey().equals("TMPDIR") &&
|
||||
!entry.getKey().equals("ANDROID_BOOTLOGO") &&
|
||||
!entry.getKey().equals("EXTERNAL_STORAGE") &&
|
||||
!entry.getKey().equals("ANDROID_ASSETS") &&
|
||||
!entry.getKey().equals("PATH") &&
|
||||
!entry.getKey().equals("TERMINFO") &&
|
||||
!entry.getKey().equals("LD_LIBRARY_PATH") &&
|
||||
!entry.getKey().equals("ANDROID_DATA") &&
|
||||
!entry.getKey().equals("ANDROID_PROPERTY_WORKSPACE") &&
|
||||
!entry.getKey().equals("ANDROID_ROOT")) {
|
||||
envstr.append(" --es env" + c + " " + entry.getKey() + "="
|
||||
+ entry.getValue());
|
||||
c++;
|
||||
}
|
||||
}
|
||||
return envstr.toString();
|
||||
}
|
||||
|
||||
public void doRestart() {
|
||||
try {
|
||||
String action = "org.mozilla.gecko.restart" + getAppName();
|
||||
String amCmd = "/system/bin/am broadcast -a " + action + getEnvString() + " -n org.mozilla." + getAppName() + "/org.mozilla." + getAppName() + ".Restarter";
|
||||
Log.i("GeckoAppJava", amCmd);
|
||||
Runtime.getRuntime().exec(amCmd);
|
||||
} catch (Exception e) {
|
||||
Log.i("GeckoAppJava", e.toString());
|
||||
}
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
219
embedding/android/GeckoAppShell.java
Normal file
219
embedding/android/GeckoAppShell.java
Normal file
@ -0,0 +1,219 @@
|
||||
/* -*- Mode: Java; tab-width: 20; indent-tabs-mode: nil; -*-
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Android code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Vladimir Vukicevic <vladimir@pobox.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
package org.mozilla.gecko;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.zip.*;
|
||||
import java.nio.*;
|
||||
|
||||
import android.os.*;
|
||||
import android.app.*;
|
||||
import android.text.*;
|
||||
import android.view.*;
|
||||
import android.view.inputmethod.*;
|
||||
import android.content.*;
|
||||
import android.graphics.*;
|
||||
import android.widget.*;
|
||||
import android.hardware.*;
|
||||
|
||||
import android.util.*;
|
||||
import android.content.DialogInterface;
|
||||
|
||||
class GeckoAppShell
|
||||
{
|
||||
static {
|
||||
sGeckoRunning = false;
|
||||
}
|
||||
|
||||
// static members only
|
||||
private GeckoAppShell() { }
|
||||
|
||||
static boolean sGeckoRunning;
|
||||
|
||||
static private boolean gRestartScheduled = false;
|
||||
|
||||
/* The Android-side API: API methods that Android calls */
|
||||
|
||||
// Initialization methods
|
||||
public static native void nativeInit();
|
||||
public static native void nativeRun(String args);
|
||||
|
||||
// helper methods
|
||||
public static native void setInitialSize(int width, int height);
|
||||
public static native void setSurfaceView(GeckoSurfaceView sv);
|
||||
public static native void putenv(String map);
|
||||
|
||||
// java-side stuff
|
||||
public static void loadGeckoLibs() {
|
||||
// The package data lib directory isn't placed in ld.so's
|
||||
// search path, so we have to manually load libraries that
|
||||
// libxul will depend on. Not ideal.
|
||||
|
||||
// MozAlloc
|
||||
System.loadLibrary("mozalloc");
|
||||
|
||||
// NSPR
|
||||
System.loadLibrary("nspr4");
|
||||
System.loadLibrary("plc4");
|
||||
System.loadLibrary("plds4");
|
||||
|
||||
// SQLite
|
||||
System.loadLibrary("mozsqlite3");
|
||||
|
||||
// NSS
|
||||
System.loadLibrary("nssutil3");
|
||||
System.loadLibrary("nss3");
|
||||
System.loadLibrary("ssl3");
|
||||
System.loadLibrary("smime3");
|
||||
|
||||
// JS
|
||||
System.loadLibrary("mozjs");
|
||||
|
||||
// XUL
|
||||
System.loadLibrary("xul");
|
||||
|
||||
// xpcom glue -- needed to load binary components
|
||||
System.loadLibrary("xpcom");
|
||||
|
||||
// Root certs. someday we may teach security/manager/ssl/src/nsNSSComponent.cpp to find ckbi itself
|
||||
System.loadLibrary("nssckbi");
|
||||
}
|
||||
|
||||
public static void runGecko(String apkPath, String args, String url) {
|
||||
// run gecko -- it will spawn its own thread
|
||||
GeckoAppShell.nativeInit();
|
||||
|
||||
// Tell Gecko where the target surface view is for rendering
|
||||
GeckoAppShell.setSurfaceView(GeckoApp.surfaceView);
|
||||
|
||||
sGeckoRunning = true;
|
||||
|
||||
// First argument is the .apk path
|
||||
String combinedArgs = apkPath;
|
||||
if (args != null)
|
||||
combinedArgs += " " + args;
|
||||
if (url != null)
|
||||
combinedArgs += " " + url;
|
||||
// and go
|
||||
GeckoAppShell.nativeRun(combinedArgs);
|
||||
}
|
||||
|
||||
private static GeckoEvent mLastDrawEvent;
|
||||
|
||||
public static void sendEventToGecko(GeckoEvent e) {
|
||||
if (sGeckoRunning)
|
||||
notifyGeckoOfEvent(e);
|
||||
}
|
||||
|
||||
// Tell the Gecko event loop that an event is available.
|
||||
public static native void notifyGeckoOfEvent(GeckoEvent event);
|
||||
|
||||
/*
|
||||
* The Gecko-side API: API methods that Gecko calls
|
||||
*/
|
||||
public static void scheduleRedraw() {
|
||||
// Redraw everything
|
||||
scheduleRedraw(0, -1, -1, -1, -1);
|
||||
}
|
||||
|
||||
public static void scheduleRedraw(int nativeWindow, int x, int y, int w, int h) {
|
||||
GeckoEvent e;
|
||||
|
||||
if (x == -1) {
|
||||
e = new GeckoEvent(GeckoEvent.DRAW, null);
|
||||
} else {
|
||||
e = new GeckoEvent(GeckoEvent.DRAW, new Rect(x, y, w, h));
|
||||
}
|
||||
|
||||
e.mNativeWindow = nativeWindow;
|
||||
|
||||
sendEventToGecko(e);
|
||||
}
|
||||
|
||||
public static void showIME(int state) {
|
||||
InputMethodManager imm = (InputMethodManager)
|
||||
GeckoApp.surfaceView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
|
||||
GeckoApp.surfaceView.mIMEState = state;
|
||||
if (state != 0)
|
||||
imm.showSoftInput(GeckoApp.surfaceView, 0);
|
||||
else
|
||||
imm.hideSoftInputFromWindow(GeckoApp.surfaceView.getWindowToken(), 0);
|
||||
}
|
||||
|
||||
public static void enableAccelerometer(boolean enable) {
|
||||
SensorManager sm = (SensorManager)
|
||||
GeckoApp.surfaceView.getContext().getSystemService(Context.SENSOR_SERVICE);
|
||||
|
||||
if (enable) {
|
||||
Sensor accelSensor = sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
|
||||
if (accelSensor == null)
|
||||
return;
|
||||
|
||||
sm.registerListener(GeckoApp.surfaceView, accelSensor, SensorManager.SENSOR_DELAY_GAME);
|
||||
} else {
|
||||
sm.unregisterListener(GeckoApp.surfaceView);
|
||||
}
|
||||
}
|
||||
|
||||
public static void returnIMEQueryResult(String result, int selectionStart, int selectionEnd) {
|
||||
GeckoApp.surfaceView.inputConnection.mSelectionStart = selectionStart;
|
||||
GeckoApp.surfaceView.inputConnection.mSelectionEnd = selectionEnd;
|
||||
try {
|
||||
GeckoApp.surfaceView.inputConnection.mQueryResult.put(result);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
|
||||
static void onXreExit() {
|
||||
sGeckoRunning = false;
|
||||
Log.i("GeckoAppJava", "XRE exited");
|
||||
if (gRestartScheduled) {
|
||||
GeckoApp.mAppContext.doRestart();
|
||||
} else {
|
||||
Log.i("GeckoAppJava", "we're done, good bye");
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
}
|
||||
static void scheduleRestart() {
|
||||
Log.i("GeckoAppJava", "scheduling restart");
|
||||
gRestartScheduled = true;
|
||||
}
|
||||
}
|
165
embedding/android/GeckoEvent.java
Normal file
165
embedding/android/GeckoEvent.java
Normal file
@ -0,0 +1,165 @@
|
||||
/* -*- Mode: Java; tab-width: 20; indent-tabs-mode: nil; -*-
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Android code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009-2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Vladimir Vukicevic <vladimir@pobox.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
package org.mozilla.gecko;
|
||||
|
||||
import android.os.*;
|
||||
import android.app.*;
|
||||
import android.view.*;
|
||||
import android.content.*;
|
||||
import android.graphics.*;
|
||||
import android.widget.*;
|
||||
import android.hardware.*;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
/* We're not allowed to hold on to most events given to us
|
||||
* so we save the parts of the events we want to use in GeckoEvent.
|
||||
* Fields have different meanings depending on the event type.
|
||||
*/
|
||||
|
||||
public class GeckoEvent {
|
||||
public static final int INVALID = -1;
|
||||
public static final int NATIVE_POKE = 0;
|
||||
public static final int KEY_EVENT = 1;
|
||||
public static final int MOTION_EVENT = 2;
|
||||
public static final int SENSOR_EVENT = 3;
|
||||
public static final int IME_EVENT = 4;
|
||||
public static final int DRAW = 5;
|
||||
public static final int SIZE_CHANGED = 6;
|
||||
public static final int ACTIVITY_STOPPING = 7;
|
||||
|
||||
public static final int IME_BATCH_END = 0;
|
||||
public static final int IME_BATCH_BEGIN = 1;
|
||||
public static final int IME_SET_TEXT = 2;
|
||||
public static final int IME_GET_TEXT = 3;
|
||||
public static final int IME_DELETE_TEXT = 4;
|
||||
|
||||
public int mType;
|
||||
public int mAction;
|
||||
public long mTime;
|
||||
public Point mP0, mP1;
|
||||
public Rect mRect;
|
||||
public float mX, mY, mZ;
|
||||
|
||||
public int mMetaState, mFlags;
|
||||
public int mKeyCode, mUnicodeChar;
|
||||
public int mCount, mCount2;
|
||||
public String mCharacters;
|
||||
|
||||
public int mNativeWindow;
|
||||
|
||||
public GeckoEvent() {
|
||||
mType = NATIVE_POKE;
|
||||
}
|
||||
|
||||
public GeckoEvent(int evType) {
|
||||
mType = evType;
|
||||
}
|
||||
|
||||
public GeckoEvent(KeyEvent k) {
|
||||
mType = KEY_EVENT;
|
||||
mAction = k.getAction();
|
||||
mTime = k.getEventTime();
|
||||
mMetaState = k.getMetaState();
|
||||
mFlags = k.getFlags();
|
||||
mKeyCode = k.getKeyCode();
|
||||
mUnicodeChar = k.getUnicodeChar();
|
||||
mCharacters = k.getCharacters();
|
||||
}
|
||||
|
||||
public GeckoEvent(MotionEvent m) {
|
||||
mType = MOTION_EVENT;
|
||||
mAction = m.getAction();
|
||||
mTime = m.getEventTime();
|
||||
mP0 = new Point((int)m.getX(), (int)m.getY());
|
||||
}
|
||||
|
||||
public GeckoEvent(SensorEvent s) {
|
||||
mType = SENSOR_EVENT;
|
||||
mX = s.values[0] / SensorManager.GRAVITY_EARTH;
|
||||
mY = s.values[1] / SensorManager.GRAVITY_EARTH;
|
||||
mZ = s.values[2] / SensorManager.GRAVITY_EARTH;
|
||||
}
|
||||
|
||||
public GeckoEvent(boolean batchEdit, String text) {
|
||||
mType = IME_EVENT;
|
||||
if (text != null)
|
||||
mAction = IME_SET_TEXT;
|
||||
else
|
||||
mAction = batchEdit ? IME_BATCH_BEGIN : IME_BATCH_END;
|
||||
mCharacters = text;
|
||||
}
|
||||
|
||||
public GeckoEvent(boolean forward, int count) {
|
||||
mType = IME_EVENT;
|
||||
mAction = IME_GET_TEXT;
|
||||
if (forward)
|
||||
mCount = count;
|
||||
else
|
||||
mCount2 = count;
|
||||
}
|
||||
|
||||
public GeckoEvent(int leftLen, int rightLen) {
|
||||
mType = IME_EVENT;
|
||||
mAction = IME_DELETE_TEXT;
|
||||
mCount = leftLen;
|
||||
mCount2 = rightLen;
|
||||
}
|
||||
|
||||
public GeckoEvent(int etype, Rect dirty) {
|
||||
if (etype != DRAW) {
|
||||
mType = INVALID;
|
||||
return;
|
||||
}
|
||||
|
||||
mType = etype;
|
||||
mRect = dirty;
|
||||
}
|
||||
|
||||
public GeckoEvent(int etype, int w, int h, int oldw, int oldh) {
|
||||
if (etype != SIZE_CHANGED) {
|
||||
mType = INVALID;
|
||||
return;
|
||||
}
|
||||
|
||||
mType = etype;
|
||||
|
||||
mP0 = new Point(w, h);
|
||||
mP1 = new Point(oldw, oldh);
|
||||
}
|
||||
}
|
838
embedding/android/GeckoSurfaceView.java
Normal file
838
embedding/android/GeckoSurfaceView.java
Normal file
@ -0,0 +1,838 @@
|
||||
/* -*- Mode: Java; tab-width: 20; indent-tabs-mode: nil; -*-
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Android code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Vladimir Vukicevic <vladimir@pobox.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
package org.mozilla.gecko;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.locks.*;
|
||||
import java.util.concurrent.atomic.*;
|
||||
import java.util.zip.*;
|
||||
import java.nio.*;
|
||||
|
||||
import javax.microedition.khronos.egl.EGL10;
|
||||
import javax.microedition.khronos.egl.EGL11;
|
||||
import javax.microedition.khronos.egl.EGLConfig;
|
||||
import javax.microedition.khronos.egl.EGLContext;
|
||||
import javax.microedition.khronos.egl.EGLDisplay;
|
||||
import javax.microedition.khronos.egl.EGLSurface;
|
||||
import javax.microedition.khronos.opengles.GL;
|
||||
import javax.microedition.khronos.opengles.GL10;
|
||||
|
||||
import android.os.*;
|
||||
import android.app.*;
|
||||
import android.text.*;
|
||||
import android.view.*;
|
||||
import android.view.inputmethod.*;
|
||||
import android.content.*;
|
||||
import android.graphics.*;
|
||||
import android.widget.*;
|
||||
import android.hardware.*;
|
||||
|
||||
import android.util.*;
|
||||
|
||||
/*
|
||||
* GeckoSurfaceView implements a GL surface view,
|
||||
* similar to GLSurfaceView. However, since we
|
||||
* already have a thread for Gecko, we don't really want
|
||||
* a separate renderer thread that GLSurfaceView provides.
|
||||
*/
|
||||
class GeckoSurfaceView
|
||||
extends SurfaceView
|
||||
implements SurfaceHolder.Callback, SensorEventListener
|
||||
{
|
||||
public GeckoSurfaceView(Context context) {
|
||||
super(context);
|
||||
|
||||
getHolder().addCallback(this);
|
||||
inputConnection = new GeckoInputConnection(this);
|
||||
setFocusable(true);
|
||||
setFocusableInTouchMode(true);
|
||||
|
||||
if (!GeckoApp.useSoftwareDrawing)
|
||||
startEgl();
|
||||
|
||||
mWidth = 0;
|
||||
mHeight = 0;
|
||||
mBufferWidth = 0;
|
||||
mBufferHeight = 0;
|
||||
|
||||
mSurfaceLock = new ReentrantLock();
|
||||
}
|
||||
|
||||
protected void finalize() throws Throwable {
|
||||
super.finalize();
|
||||
if (!GeckoApp.useSoftwareDrawing)
|
||||
finishEgl();
|
||||
}
|
||||
|
||||
private static final int EGL_OPENGL_ES2_BIT = 4;
|
||||
private static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
|
||||
|
||||
private void printConfig(EGL10 egl, EGLDisplay display,
|
||||
EGLConfig config) {
|
||||
int[] attributes = {
|
||||
EGL10.EGL_BUFFER_SIZE,
|
||||
EGL10.EGL_ALPHA_SIZE,
|
||||
EGL10.EGL_BLUE_SIZE,
|
||||
EGL10.EGL_GREEN_SIZE,
|
||||
EGL10.EGL_RED_SIZE,
|
||||
EGL10.EGL_DEPTH_SIZE,
|
||||
EGL10.EGL_STENCIL_SIZE,
|
||||
EGL10.EGL_CONFIG_CAVEAT,
|
||||
EGL10.EGL_CONFIG_ID,
|
||||
EGL10.EGL_LEVEL,
|
||||
EGL10.EGL_MAX_PBUFFER_HEIGHT,
|
||||
EGL10.EGL_MAX_PBUFFER_PIXELS,
|
||||
EGL10.EGL_MAX_PBUFFER_WIDTH,
|
||||
EGL10.EGL_NATIVE_RENDERABLE,
|
||||
EGL10.EGL_NATIVE_VISUAL_ID,
|
||||
EGL10.EGL_NATIVE_VISUAL_TYPE,
|
||||
0x3030, // EGL10.EGL_PRESERVED_RESOURCES,
|
||||
EGL10.EGL_SAMPLES,
|
||||
EGL10.EGL_SAMPLE_BUFFERS,
|
||||
EGL10.EGL_SURFACE_TYPE,
|
||||
EGL10.EGL_TRANSPARENT_TYPE,
|
||||
EGL10.EGL_TRANSPARENT_RED_VALUE,
|
||||
EGL10.EGL_TRANSPARENT_GREEN_VALUE,
|
||||
EGL10.EGL_TRANSPARENT_BLUE_VALUE,
|
||||
0x3039, // EGL10.EGL_BIND_TO_TEXTURE_RGB,
|
||||
0x303A, // EGL10.EGL_BIND_TO_TEXTURE_RGBA,
|
||||
0x303B, // EGL10.EGL_MIN_SWAP_INTERVAL,
|
||||
0x303C, // EGL10.EGL_MAX_SWAP_INTERVAL,
|
||||
EGL10.EGL_LUMINANCE_SIZE,
|
||||
EGL10.EGL_ALPHA_MASK_SIZE,
|
||||
EGL10.EGL_COLOR_BUFFER_TYPE,
|
||||
EGL10.EGL_RENDERABLE_TYPE,
|
||||
0x3042 // EGL10.EGL_CONFORMANT
|
||||
};
|
||||
String[] names = {
|
||||
"EGL_BUFFER_SIZE",
|
||||
"EGL_ALPHA_SIZE",
|
||||
"EGL_BLUE_SIZE",
|
||||
"EGL_GREEN_SIZE",
|
||||
"EGL_RED_SIZE",
|
||||
"EGL_DEPTH_SIZE",
|
||||
"EGL_STENCIL_SIZE",
|
||||
"EGL_CONFIG_CAVEAT",
|
||||
"EGL_CONFIG_ID",
|
||||
"EGL_LEVEL",
|
||||
"EGL_MAX_PBUFFER_HEIGHT",
|
||||
"EGL_MAX_PBUFFER_PIXELS",
|
||||
"EGL_MAX_PBUFFER_WIDTH",
|
||||
"EGL_NATIVE_RENDERABLE",
|
||||
"EGL_NATIVE_VISUAL_ID",
|
||||
"EGL_NATIVE_VISUAL_TYPE",
|
||||
"EGL_PRESERVED_RESOURCES",
|
||||
"EGL_SAMPLES",
|
||||
"EGL_SAMPLE_BUFFERS",
|
||||
"EGL_SURFACE_TYPE",
|
||||
"EGL_TRANSPARENT_TYPE",
|
||||
"EGL_TRANSPARENT_RED_VALUE",
|
||||
"EGL_TRANSPARENT_GREEN_VALUE",
|
||||
"EGL_TRANSPARENT_BLUE_VALUE",
|
||||
"EGL_BIND_TO_TEXTURE_RGB",
|
||||
"EGL_BIND_TO_TEXTURE_RGBA",
|
||||
"EGL_MIN_SWAP_INTERVAL",
|
||||
"EGL_MAX_SWAP_INTERVAL",
|
||||
"EGL_LUMINANCE_SIZE",
|
||||
"EGL_ALPHA_MASK_SIZE",
|
||||
"EGL_COLOR_BUFFER_TYPE",
|
||||
"EGL_RENDERABLE_TYPE",
|
||||
"EGL_CONFORMANT"
|
||||
};
|
||||
int[] value = new int[1];
|
||||
for (int i = 0; i < attributes.length; i++) {
|
||||
int attribute = attributes[i];
|
||||
String name = names[i];
|
||||
if ( egl.eglGetConfigAttrib(display, config, attribute, value)) {
|
||||
Log.w("GeckoAppJava", String.format(" %s: %d\n", name, value[0]));
|
||||
} else {
|
||||
Log.w("GeckoAppJava", String.format(" %s: failed\n", name));
|
||||
// while (egl.eglGetError() != EGL10.EGL_SUCCESS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void startEgl() {
|
||||
if (mEgl != null)
|
||||
return;
|
||||
|
||||
mEgl = (EGL10) EGLContext.getEGL();
|
||||
mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
|
||||
|
||||
// initialize egl
|
||||
int[] version = new int[2];
|
||||
mEgl.eglInitialize(mEglDisplay, version);
|
||||
|
||||
// flip this to true to dump all the EGL configs
|
||||
if (false) {
|
||||
int[] cs = { EGL10.EGL_NONE };
|
||||
int[] ptrnum = new int[1];
|
||||
|
||||
mEgl.eglChooseConfig(mEglDisplay, cs, null, 0, ptrnum);
|
||||
|
||||
int num = ptrnum[0];
|
||||
EGLConfig[] confs = new EGLConfig[num];
|
||||
|
||||
mEgl.eglChooseConfig(mEglDisplay, cs, confs, num, ptrnum);
|
||||
|
||||
for (int i = 0; i < num; ++i) {
|
||||
Log.w("GeckoAppJava", "=== EGL config " + i + " ===");
|
||||
printConfig(mEgl, mEglDisplay, confs[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void finishEgl() {
|
||||
if (mEglDisplay != null) {
|
||||
mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
|
||||
EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
|
||||
}
|
||||
|
||||
if (mEglContext != null) {
|
||||
mEgl.eglDestroyContext(mEglDisplay, mEglContext);
|
||||
mEglContext = null;
|
||||
}
|
||||
|
||||
if (mEglSurface != null) {
|
||||
mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
|
||||
mEglSurface = null;
|
||||
}
|
||||
|
||||
if (mEglDisplay != null) {
|
||||
mEgl.eglTerminate(mEglDisplay);
|
||||
mEglDisplay = null;
|
||||
}
|
||||
|
||||
mEglConfig = null;
|
||||
mEgl = null;
|
||||
|
||||
mSurfaceChanged = false;
|
||||
}
|
||||
|
||||
public void chooseEglConfig() {
|
||||
int redBits, greenBits, blueBits, alphaBits;
|
||||
|
||||
// There are some shenanigans here.
|
||||
// We're required to choose an exact EGL config to match
|
||||
// the surface format, or we get an error. However,
|
||||
// on Droid at least, the format is -1, which is PixelFormat.OPAQUE.
|
||||
// That's not a valid format to be reported; that should just be a
|
||||
// valid value for *setFormat*. We have a catch-all case that
|
||||
// assumes 565 for those cases, but it's pretty ugly.
|
||||
|
||||
Log.i("GeckoAppJava", "GeckoView PixelFormat format is " + mFormat);
|
||||
if (mFormat == PixelFormat.RGB_565) {
|
||||
redBits = 5;
|
||||
greenBits = 6;
|
||||
blueBits = 5;
|
||||
alphaBits = 0;
|
||||
} else if (mFormat == PixelFormat.RGB_888 ||
|
||||
mFormat == PixelFormat.RGBX_8888)
|
||||
{
|
||||
redBits = 8;
|
||||
greenBits = 8;
|
||||
blueBits = 8;
|
||||
alphaBits = 0;
|
||||
} else if (mFormat == PixelFormat.RGBA_8888) {
|
||||
redBits = 8;
|
||||
greenBits = 8;
|
||||
blueBits = 8;
|
||||
alphaBits = 8;
|
||||
} else {
|
||||
Log.w("GeckoAppJava", "Unknown PixelFormat for surface (format is " + mFormat + "), assuming 5650!");
|
||||
redBits = 5;
|
||||
greenBits = 6;
|
||||
blueBits = 5;
|
||||
alphaBits = 0;
|
||||
}
|
||||
|
||||
// PowerVR SGX (Droid) seems to really want depth == 24 for
|
||||
// performance, even 0 is slower. However, other platforms,
|
||||
// like Tegra, don't -have- a 24 bit depth config (have 16).
|
||||
// So that's not good. We'll try with 24 first, and if
|
||||
// nothing, then we'll go to 0. I'm not sure what the nexus
|
||||
// one chip wants.
|
||||
|
||||
int[] confSpec = new int[] {
|
||||
// DEPTH_SIZE must be the first pair
|
||||
EGL10.EGL_DEPTH_SIZE, 24,
|
||||
EGL10.EGL_RED_SIZE, redBits,
|
||||
EGL10.EGL_GREEN_SIZE, greenBits,
|
||||
EGL10.EGL_BLUE_SIZE, blueBits,
|
||||
EGL10.EGL_ALPHA_SIZE, alphaBits,
|
||||
EGL10.EGL_STENCIL_SIZE, 0,
|
||||
EGL10.EGL_CONFIG_CAVEAT, EGL10.EGL_NONE,
|
||||
EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
|
||||
EGL10.EGL_NONE };
|
||||
|
||||
// so tortured to pass an int as an out param...
|
||||
int[] ptrNumConfigs = new int[1];
|
||||
mEgl.eglChooseConfig(mEglDisplay, confSpec, null, 0, ptrNumConfigs);
|
||||
|
||||
int numConfigs = ptrNumConfigs[0];
|
||||
|
||||
if (numConfigs == 0) {
|
||||
// twiddle the DEPTH_SIZE value
|
||||
confSpec[1] = 0;
|
||||
Log.i("GeckoAppJava", "Couldn't find any valid EGL configs with 24 bit depth, trying 0.");
|
||||
|
||||
mEgl.eglChooseConfig(mEglDisplay, confSpec, null, 0, ptrNumConfigs);
|
||||
numConfigs = ptrNumConfigs[0];
|
||||
}
|
||||
|
||||
if (numConfigs <= 0) {
|
||||
// couldn't find a config?
|
||||
Log.w("GeckoAppJava", "Couldn't find any valid EGL configs, blindly trying them all!");
|
||||
|
||||
int[] fallbackConfSpec = new int[] {
|
||||
EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
|
||||
EGL10.EGL_NONE };
|
||||
confSpec = fallbackConfSpec;
|
||||
|
||||
mEgl.eglChooseConfig(mEglDisplay, confSpec, null, 0, ptrNumConfigs);
|
||||
numConfigs = ptrNumConfigs[0];
|
||||
|
||||
if (numConfigs == 0) {
|
||||
Log.e("GeckoAppJava", "There aren't any EGL configs available on this system.");
|
||||
finishEgl();
|
||||
mSurfaceValid = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
EGLConfig[] configs = new EGLConfig[numConfigs];
|
||||
mEgl.eglChooseConfig(mEglDisplay, confSpec, configs, numConfigs, ptrNumConfigs);
|
||||
|
||||
// Find the first config that has the exact RGB sizes that we
|
||||
// need for our window surface.
|
||||
int[] ptrVal = new int[1];
|
||||
for (int i = 0; i < configs.length; ++i) {
|
||||
int confRed = -1, confGreen = -1, confBlue = -1, confAlpha = -1;
|
||||
|
||||
if (mEgl.eglGetConfigAttrib(mEglDisplay, configs[i], EGL10.EGL_RED_SIZE, ptrVal))
|
||||
confRed = ptrVal[0];
|
||||
if (mEgl.eglGetConfigAttrib(mEglDisplay, configs[i], EGL10.EGL_GREEN_SIZE, ptrVal))
|
||||
confGreen = ptrVal[0];
|
||||
if (mEgl.eglGetConfigAttrib(mEglDisplay, configs[i], EGL10.EGL_BLUE_SIZE, ptrVal))
|
||||
confBlue = ptrVal[0];
|
||||
if (mEgl.eglGetConfigAttrib(mEglDisplay, configs[i], EGL10.EGL_ALPHA_SIZE, ptrVal))
|
||||
confAlpha = ptrVal[0];
|
||||
|
||||
if (confRed == redBits &&
|
||||
confGreen == greenBits &&
|
||||
confBlue == blueBits &&
|
||||
confAlpha == alphaBits)
|
||||
{
|
||||
mEglConfig = configs[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mEglConfig == null) {
|
||||
Log.w("GeckoAppJava", "Couldn't find EGL config matching colors; using first, hope it works!");
|
||||
mEglConfig = configs[0];
|
||||
}
|
||||
|
||||
Log.i("GeckoAppJava", "====== Chosen config: ======");
|
||||
printConfig(mEgl, mEglDisplay, mEglConfig);
|
||||
|
||||
mEglContext = null;
|
||||
mEglSurface = null;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called on main thread
|
||||
*/
|
||||
|
||||
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
|
||||
mSurfaceLock.lock();
|
||||
|
||||
try {
|
||||
if (mInDrawing) {
|
||||
Log.w("GeckoAppJava", "surfaceChanged while mInDrawing is true!");
|
||||
}
|
||||
|
||||
mFormat = format;
|
||||
mWidth = width;
|
||||
mHeight = height;
|
||||
mSurfaceValid = true;
|
||||
|
||||
Log.i("GeckoAppJava", "surfaceChanged: fmt: " + format + " dim: " + width + " " + height);
|
||||
|
||||
if (!GeckoApp.useSoftwareDrawing) {
|
||||
chooseEglConfig();
|
||||
}
|
||||
|
||||
// XXX This code doesn't seem to actually get hit
|
||||
if (!GeckoAppShell.sGeckoRunning) {
|
||||
GeckoAppShell.setInitialSize(width, height);
|
||||
return;
|
||||
}
|
||||
|
||||
GeckoEvent e = new GeckoEvent(GeckoEvent.SIZE_CHANGED, width, height, -1, -1);
|
||||
GeckoAppShell.sendEventToGecko(e);
|
||||
|
||||
if (mSurfaceNeedsRedraw) {
|
||||
GeckoAppShell.scheduleRedraw();
|
||||
mSurfaceNeedsRedraw = false;
|
||||
}
|
||||
|
||||
mSurfaceChanged = true;
|
||||
|
||||
//Log.i("GeckoAppJava", "<< surfaceChanged");
|
||||
} finally {
|
||||
mSurfaceLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void surfaceCreated(SurfaceHolder holder) {
|
||||
if (GeckoAppShell.sGeckoRunning)
|
||||
mSurfaceNeedsRedraw = true;
|
||||
}
|
||||
|
||||
public void surfaceDestroyed(SurfaceHolder holder) {
|
||||
Log.i("GeckoAppJava", "surface destroyed");
|
||||
mSurfaceValid = false;
|
||||
}
|
||||
|
||||
public ByteBuffer getSoftwareDrawBuffer() {
|
||||
//#ifdef DEBUG
|
||||
if (!mSurfaceLock.isHeldByCurrentThread())
|
||||
Log.e("GeckoAppJava", "getSoftwareDrawBuffer called outside of mSurfaceLock!");
|
||||
//#endif
|
||||
|
||||
return mSoftwareBuffer;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called on Gecko thread
|
||||
*/
|
||||
|
||||
public static final int DRAW_ERROR = 0;
|
||||
public static final int DRAW_GLES_2 = 1;
|
||||
public static final int DRAW_SOFTWARE = 2;
|
||||
|
||||
int innerBeginDrawing() {
|
||||
/*
|
||||
* Software (non-GL) rendering
|
||||
*/
|
||||
if (GeckoApp.useSoftwareDrawing) {
|
||||
if (mWidth != mBufferWidth ||
|
||||
mHeight != mBufferHeight ||
|
||||
mSurfaceChanged)
|
||||
{
|
||||
if (mWidth*mHeight != mBufferWidth*mBufferHeight)
|
||||
mSoftwareBuffer = ByteBuffer.allocateDirect(mWidth*mHeight*4);
|
||||
|
||||
mSoftwareBitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_8888);
|
||||
|
||||
mBufferWidth = mWidth;
|
||||
mBufferHeight = mHeight;
|
||||
mSurfaceChanged = false;
|
||||
}
|
||||
|
||||
mSoftwareCanvas = getHolder().lockCanvas(null);
|
||||
if (mSoftwareCanvas == null) {
|
||||
Log.e("GeckoAppJava", "lockCanvas failed! << beginDrawing");
|
||||
return DRAW_ERROR;
|
||||
}
|
||||
|
||||
return DRAW_SOFTWARE;
|
||||
}
|
||||
|
||||
/*
|
||||
* GL rendering
|
||||
*/
|
||||
|
||||
if (mEgl == null || mEglDisplay == null || mEglConfig == null) {
|
||||
Log.e("GeckoAppJava", "beginDrawing called, but EGL was never initialized!");
|
||||
|
||||
mSurfaceLock.unlock();
|
||||
return DRAW_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the surface doesn't exist, or if its dimensions or something else changed,
|
||||
* recreate it.
|
||||
*/
|
||||
if (mEglSurface == null ||
|
||||
mWidth != mBufferWidth ||
|
||||
mHeight != mBufferHeight ||
|
||||
mSurfaceChanged)
|
||||
{
|
||||
if (mEglContext != null) {
|
||||
mEgl.eglDestroyContext(mEglDisplay, mEglContext);
|
||||
mEglContext = null;
|
||||
}
|
||||
|
||||
if (mEglSurface != null)
|
||||
mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
|
||||
|
||||
mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig, getHolder(), null);
|
||||
if (mEglSurface == EGL10.EGL_NO_SURFACE)
|
||||
{
|
||||
Log.e("GeckoAppJava", "eglCreateWindowSurface failed!");
|
||||
mSurfaceValid = false;
|
||||
return DRAW_ERROR;
|
||||
}
|
||||
|
||||
mBufferWidth = mWidth;
|
||||
mBufferHeight = mHeight;
|
||||
|
||||
mSurfaceChanged = false;
|
||||
}
|
||||
|
||||
if (mEglContext == null) {
|
||||
int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, 2,
|
||||
EGL10.EGL_NONE };
|
||||
mEglContext = mEgl.eglCreateContext(mEglDisplay, mEglConfig, EGL10.EGL_NO_CONTEXT, attrib_list);
|
||||
if (mEglContext == EGL10.EGL_NO_CONTEXT)
|
||||
{
|
||||
Log.e("GeckoAppJava", "eglCreateContext failed! " + mEgl.eglGetError());
|
||||
mSurfaceValid = false;
|
||||
return DRAW_ERROR;
|
||||
}
|
||||
|
||||
Log.i("GeckoAppJava", "EglContext created");
|
||||
}
|
||||
|
||||
// Hmm, should we issue this makecurrent for each frame?
|
||||
// We'll likely have to, as other bits might switch the context (e.g.
|
||||
// WebGL, video, etc.).
|
||||
|
||||
if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
|
||||
int err = mEgl.eglGetError();
|
||||
Log.e("GeckoAppJava", "eglMakeCurrent failed! " + err);
|
||||
return DRAW_ERROR;
|
||||
}
|
||||
|
||||
return DRAW_GLES_2;
|
||||
}
|
||||
|
||||
public int beginDrawing() {
|
||||
//Log.i("GeckoAppJava", ">> beginDrawing");
|
||||
|
||||
if (mInDrawing) {
|
||||
Log.e("GeckoAppJava", "Recursive beginDrawing call!");
|
||||
return DRAW_ERROR;
|
||||
}
|
||||
|
||||
/* Grab the lock, which we'll hold while we're drawing.
|
||||
* It gets released in endDrawing(), and is also used in surfaceChanged
|
||||
* to make sure that we don't change our surface details while
|
||||
* we're in the middle of drawing (and especially in the middle of
|
||||
* executing beginDrawing/endDrawing).
|
||||
*
|
||||
* We might not need to hold this lock in between
|
||||
* beginDrawing/endDrawing, and might just be able to make
|
||||
* surfaceChanged, beginDrawing, and endDrawing synchronized,
|
||||
* but this way is safer for now.
|
||||
*/
|
||||
mSurfaceLock.lock();
|
||||
|
||||
if (!mSurfaceValid) {
|
||||
Log.e("GeckoAppJava", "Surface not valid");
|
||||
mSurfaceLock.unlock();
|
||||
return DRAW_ERROR;
|
||||
}
|
||||
|
||||
// call the inner function to do the work, so we can sanely unlock on error
|
||||
int result = innerBeginDrawing();
|
||||
|
||||
if (result == DRAW_ERROR) {
|
||||
mSurfaceLock.unlock();
|
||||
return DRAW_ERROR;
|
||||
}
|
||||
|
||||
mInDrawing = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
public void endDrawing() {
|
||||
//Log.w("GeckoAppJava", ">> endDrawing");
|
||||
|
||||
if (!mInDrawing) {
|
||||
Log.e("GeckoAppJava", "endDrawing without beginDrawing!");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (!mSurfaceValid) {
|
||||
Log.e("GeckoAppJava", "endDrawing with false mSurfaceValid");
|
||||
return;
|
||||
}
|
||||
|
||||
if (GeckoApp.useSoftwareDrawing) {
|
||||
if (!mSurfaceChanged) {
|
||||
mSoftwareBitmap.copyPixelsFromBuffer(mSoftwareBuffer);
|
||||
mSoftwareCanvas.drawBitmap(mSoftwareBitmap, 0, 0, null);
|
||||
|
||||
getHolder().unlockCanvasAndPost(mSoftwareCanvas);
|
||||
mSoftwareCanvas = null;
|
||||
}
|
||||
} else {
|
||||
// If the surface was changed while we were drawing;
|
||||
// don't even bother trying to swap, it won't work,
|
||||
// and may cause further problems. Note that
|
||||
// eglSwapBuffers might also throw an
|
||||
// IllegalArgumentException; we catch that as well.
|
||||
if (!mSurfaceChanged) {
|
||||
mEgl.eglSwapBuffers(mEglDisplay, mEglSurface);
|
||||
if (mEgl.eglGetError() == EGL11.EGL_CONTEXT_LOST)
|
||||
mSurfaceChanged = true;
|
||||
}
|
||||
}
|
||||
} catch (java.lang.IllegalArgumentException ex) {
|
||||
mSurfaceChanged = true;
|
||||
} finally {
|
||||
mInDrawing = false;
|
||||
|
||||
//#ifdef DEBUG
|
||||
if (!mSurfaceLock.isHeldByCurrentThread())
|
||||
Log.e("GeckoAppJava", "endDrawing while mSurfaceLock not held by current thread!");
|
||||
//#endif
|
||||
|
||||
mSurfaceLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCheckIsTextEditor () {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
|
||||
outAttrs.inputType = InputType.TYPE_CLASS_TEXT |
|
||||
InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS;
|
||||
return inputConnection;
|
||||
}
|
||||
|
||||
public void onAccuracyChanged(Sensor sensor, int accuracy)
|
||||
{
|
||||
}
|
||||
|
||||
public void onSensorChanged(SensorEvent event)
|
||||
{
|
||||
GeckoAppShell.sendEventToGecko(new GeckoEvent(event));
|
||||
}
|
||||
|
||||
// event stuff
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
GeckoAppShell.sendEventToGecko(new GeckoEvent(event));
|
||||
return true;
|
||||
}
|
||||
|
||||
// Is this surface valid for drawing into?
|
||||
boolean mSurfaceValid;
|
||||
|
||||
// Do we need to force a redraw on surfaceChanged?
|
||||
boolean mSurfaceNeedsRedraw;
|
||||
|
||||
// Has this surface been changed? (That is,
|
||||
// do we need to recreate buffers?)
|
||||
boolean mSurfaceChanged;
|
||||
|
||||
// Are we actively between beginDrawing/endDrawing?
|
||||
boolean mInDrawing;
|
||||
|
||||
// let's not change stuff around while we're in the middle of
|
||||
// starting drawing, ending drawing, or changing surface
|
||||
// characteristics
|
||||
ReentrantLock mSurfaceLock;
|
||||
|
||||
// Surface format, from surfaceChanged. Largely
|
||||
// useless.
|
||||
int mFormat;
|
||||
|
||||
// the dimensions of the surface
|
||||
int mWidth;
|
||||
int mHeight;
|
||||
|
||||
// the dimensions of the buffer we're using for drawing,
|
||||
// that is the software buffer or the EGLSurface
|
||||
int mBufferWidth;
|
||||
int mBufferHeight;
|
||||
|
||||
// IME stuff
|
||||
GeckoInputConnection inputConnection;
|
||||
int mIMEState;
|
||||
|
||||
// Software rendering
|
||||
ByteBuffer mSoftwareBuffer;
|
||||
Bitmap mSoftwareBitmap;
|
||||
Canvas mSoftwareCanvas;
|
||||
|
||||
// GL rendering
|
||||
EGL10 mEgl;
|
||||
EGLDisplay mEglDisplay;
|
||||
EGLSurface mEglSurface;
|
||||
EGLConfig mEglConfig;
|
||||
EGLContext mEglContext;
|
||||
}
|
||||
|
||||
class GeckoInputConnection
|
||||
extends BaseInputConnection
|
||||
{
|
||||
public GeckoInputConnection (View targetView) {
|
||||
super(targetView, true);
|
||||
mQueryResult = new SynchronousQueue<String>();
|
||||
mExtractedText.partialStartOffset = -1;
|
||||
mExtractedText.partialEndOffset = -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Editable getEditable() {
|
||||
Log.i("GeckoAppJava", "getEditable");
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean beginBatchEdit() {
|
||||
if (mComposing)
|
||||
return true;
|
||||
GeckoAppShell.sendEventToGecko(new GeckoEvent(true, null));
|
||||
mComposing = true;
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean commitCompletion(CompletionInfo text) {
|
||||
Log.i("GeckoAppJava", "Stub: commitCompletion");
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean commitText(CharSequence text, int newCursorPosition) {
|
||||
GeckoAppShell.sendEventToGecko(new GeckoEvent(true, text.toString()));
|
||||
endBatchEdit();
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean deleteSurroundingText(int leftLength, int rightLength) {
|
||||
GeckoAppShell.sendEventToGecko(new GeckoEvent(leftLength, rightLength));
|
||||
updateExtractedText();
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean endBatchEdit() {
|
||||
updateExtractedText();
|
||||
if (!mComposing)
|
||||
return true;
|
||||
GeckoAppShell.sendEventToGecko(new GeckoEvent(false, null));
|
||||
mComposing = false;
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean finishComposingText() {
|
||||
endBatchEdit();
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public int getCursorCapsMode(int reqModes) {
|
||||
return 0;
|
||||
}
|
||||
@Override
|
||||
public ExtractedText getExtractedText(ExtractedTextRequest req, int flags) {
|
||||
mExtractToken = req.token;
|
||||
GeckoAppShell.sendEventToGecko(new GeckoEvent(false, 0));
|
||||
try {
|
||||
mExtractedText.text = mQueryResult.take();
|
||||
mExtractedText.selectionStart = mSelectionStart;
|
||||
mExtractedText.selectionEnd = mSelectionEnd;
|
||||
} catch (InterruptedException e) {
|
||||
Log.i("GeckoAppJava", "getExtractedText: Interrupted!");
|
||||
}
|
||||
return mExtractedText;
|
||||
}
|
||||
@Override
|
||||
public CharSequence getTextAfterCursor(int length, int flags) {
|
||||
GeckoAppShell.sendEventToGecko(new GeckoEvent(true, length));
|
||||
try {
|
||||
String result = mQueryResult.take();
|
||||
return result;
|
||||
} catch (InterruptedException e) {
|
||||
Log.i("GeckoAppJava", "getTextAfterCursor: Interrupted!");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public CharSequence getTextBeforeCursor(int length, int flags) {
|
||||
GeckoAppShell.sendEventToGecko(new GeckoEvent(false, length));
|
||||
try {
|
||||
String result = mQueryResult.take();
|
||||
return result;
|
||||
} catch (InterruptedException e) {
|
||||
Log.i("GeckoAppJava", "getTextBeforeCursor: Interrupted!");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public boolean setComposingText(CharSequence text, int newCursorPosition) {
|
||||
beginBatchEdit();
|
||||
GeckoAppShell.sendEventToGecko(new GeckoEvent(true, text.toString()));
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean setSelection(int start, int end) {
|
||||
Log.i("GeckoAppJava", "Stub: setSelection " + start + " " + end);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void updateExtractedText() {
|
||||
GeckoAppShell.sendEventToGecko(new GeckoEvent(false, 0));
|
||||
try {
|
||||
mExtractedText.text = mQueryResult.take();
|
||||
mExtractedText.selectionStart = mSelectionStart;
|
||||
mExtractedText.selectionEnd = mSelectionEnd;
|
||||
} catch (InterruptedException e) {
|
||||
Log.i("GeckoAppJava", "getExtractedText: Interrupted!");
|
||||
}
|
||||
|
||||
InputMethodManager imm = (InputMethodManager)
|
||||
GeckoApp.surfaceView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
imm.updateExtractedText(GeckoApp.surfaceView, mExtractToken, mExtractedText);
|
||||
}
|
||||
|
||||
boolean mComposing;
|
||||
int mExtractToken;
|
||||
final ExtractedText mExtractedText = new ExtractedText();
|
||||
|
||||
int mSelectionStart, mSelectionEnd;
|
||||
SynchronousQueue<String> mQueryResult;
|
||||
}
|
182
embedding/android/Makefile.in
Normal file
182
embedding/android/Makefile.in
Normal file
@ -0,0 +1,182 @@
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is the Mozilla browser.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Mozilla Foundation
|
||||
# Portions created by the Initial Developer are Copyright (C) 2009-2010
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Vladimir Vukicevic <vladimir@pobox.com>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
DEPTH = ../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
DX=$(ANDROID_SDK)/tools/dx
|
||||
AAPT=$(ANDROID_SDK)/tools/aapt
|
||||
APKBUILDER=$(ANDROID_SDK)/../../tools/apkbuilder
|
||||
ZIPALIGN=$(ANDROID_SDK)/../../tools/zipalign
|
||||
|
||||
JAVAFILES = \
|
||||
GeckoApp.java \
|
||||
GeckoAppShell.java \
|
||||
GeckoEvent.java \
|
||||
GeckoSurfaceView.java \
|
||||
$(NULL)
|
||||
|
||||
DEFINES += \
|
||||
-DMOZ_APP_DISPLAYNAME=$(MOZ_APP_DISPLAYNAME) \
|
||||
-DMOZ_APP_NAME=$(MOZ_APP_NAME)
|
||||
|
||||
GARBAGE += \
|
||||
AndroidManifest.xml \
|
||||
classes.dex \
|
||||
$(MOZ_APP_NAME).apk \
|
||||
App.java \
|
||||
Restarter.java \
|
||||
gecko.ap_ \
|
||||
gecko-unaligned.apk \
|
||||
gecko-unsigned-unaligned.apk \
|
||||
$(NULL)
|
||||
|
||||
GARBAGE_DIRS += res libs dist classes
|
||||
|
||||
ifdef JARSIGNER
|
||||
APKBUILDER_FLAGS += -u
|
||||
endif
|
||||
|
||||
# Bug 567884 - Need a way to find appropriate icons during packaging
|
||||
ifeq ($(MOZ_APP_NAME),fennec)
|
||||
ICON_PATH = $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/content/fennec_48x48.png
|
||||
ICON_PATH_HI = $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/content/fennec_72x72.png
|
||||
else
|
||||
ICON_PATH = $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/content/icon48.png
|
||||
ICON_PATH_HI = $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/content/icon64.png
|
||||
endif
|
||||
|
||||
NATIVE_LIBS = $(shell cat $(DIST)/bin/dependentlibs.list) libxpcom.so libnssckbi.so libfreebl3.so
|
||||
FULL_LIBS = $(addprefix libs/armeabi/,$(NATIVE_LIBS))
|
||||
|
||||
# We'll strip all the libs by default, due to size, but we might
|
||||
# want to have a non-stripped version for debugging. We should
|
||||
# really pull out debuginfo and stuff.
|
||||
ifdef NO_STRIP
|
||||
DO_STRIP=echo not stripping
|
||||
else
|
||||
DO_STRIP=$(STRIP)
|
||||
endif
|
||||
|
||||
# The set of files/directories from the dist/bin dir that we'll make available in the apk
|
||||
# some directories not listed due to special handling
|
||||
DIST_LINK_FILES = \
|
||||
modules \
|
||||
res \
|
||||
application.ini \
|
||||
platform.ini \
|
||||
greprefs.js \
|
||||
browserconfig.properties \
|
||||
blocklist.xml \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
# rules.mk has some java stuff, but we're going to ignore it for now
|
||||
JAVAC_FLAGS = \
|
||||
-target 1.5 \
|
||||
-classpath $(ANDROID_SDK)/android.jar \
|
||||
-bootclasspath $(ANDROID_SDK)/android.jar \
|
||||
-encoding ascii \
|
||||
-g \
|
||||
$(NULL)
|
||||
|
||||
tools:: $(MOZ_APP_NAME).apk
|
||||
|
||||
# Note that we're going to set up a dependency directly between embed_android.dex and the java files
|
||||
# Instead of on the .class files, since more than one .class file might be produced per .java file
|
||||
classes.dex: $(JAVAFILES) App.java Restarter.java
|
||||
$(NSINSTALL) -D classes
|
||||
$(JAVAC) $(JAVAC_FLAGS) -d classes $(addprefix $(srcdir)/,$(JAVAFILES)) App.java Restarter.java
|
||||
$(DX) --dex --output=$@ classes
|
||||
|
||||
AndroidManifest.xml App.java Restarter.java : % : %.in
|
||||
$(PYTHON) $(topsrcdir)/config/Preprocessor.py \
|
||||
$(AUTOMATION_PPARGS) $(DEFINES) $(ACDEFINES) $< > $@
|
||||
|
||||
res/drawable/icon.png: $(MOZ_APP_ICON)
|
||||
$(NSINSTALL) -D res/drawable
|
||||
cp $(ICON_PATH) $@
|
||||
|
||||
res/drawable-hdpi/icon.png: $(MOZ_APP_ICON)
|
||||
$(NSINSTALL) -D res/drawable-hdpi
|
||||
cp $(ICON_PATH_HI) $@
|
||||
|
||||
gecko.ap_: AndroidManifest.xml res/drawable/icon.png res/drawable-hdpi/icon.png
|
||||
$(AAPT) package -f -M AndroidManifest.xml -I $(ANDROID_SDK)/android.jar -S res -F $@
|
||||
|
||||
libs/armeabi/%: $(DIST)/lib/%
|
||||
@$(NSINSTALL) -D libs/armeabi
|
||||
@cp -L -v $< $@
|
||||
@$(DO_STRIP) $@
|
||||
|
||||
# Bug 567873 - Android packaging should use standard packaging code
|
||||
dist: FORCE
|
||||
$(NSINSTALL) -D dist/components
|
||||
rm -f dist/components/*
|
||||
@(for f in $(DIST)/bin/components/* ; do ln -sf ../../$$f dist/components ; done)
|
||||
$(DIST)/host/bin/host_xpt_link gecko.xpt dist/components/*.xpt
|
||||
rm dist/components/*.xpt
|
||||
mv gecko.xpt dist/components
|
||||
$(NSINSTALL) -D dist/chrome
|
||||
rm -f dist/chrome/*
|
||||
@(for f in $(DIST)/bin/chrome/* ; do ln -sf ../../$$f dist/chrome ; done)
|
||||
@(for MANIFEST in dist/chrome/*.manifest ; do cat "$$MANIFEST" >> chrome.manifest ; echo >> chrome.manifest; rm "$$MANIFEST" ; done )
|
||||
mv chrome.manifest dist/chrome/
|
||||
$(NSINSTALL) -D dist/defaults
|
||||
rm -f dist/defaults/*
|
||||
@(for f in $(DIST)/bin/defaults/* ; do ln -sf ../../$$f dist/defaults ; done )
|
||||
@(for PREF in $(DIST)/bin/defaults/pref/*.js ; do cat "$$PREF" >> dist/defaults/prefs.js ; echo >> dist/defaults/prefs.js ; done )
|
||||
rm dist/defaults/pref
|
||||
@(for f in $(DIST_LINK_FILES) ; do if [ -e $(DIST)/bin/$$f ] ; then echo $$f ; ln -sf ../$(DIST)/bin/$$f dist ; fi ; done)
|
||||
|
||||
gecko-unsigned-unaligned.apk: gecko.ap_ classes.dex dist $(FULL_LIBS)
|
||||
$(APKBUILDER) $@ -v $(APKBUILDER_FLAGS) -z gecko.ap_ -f classes.dex -nf `pwd`/libs -rf dist
|
||||
|
||||
gecko-unaligned.apk: gecko-unsigned-unaligned.apk
|
||||
cp gecko-unsigned-unaligned.apk $@
|
||||
ifdef JARSIGNER
|
||||
$(JARSIGNER) $@
|
||||
endif
|
||||
|
||||
$(MOZ_APP_NAME).apk: gecko-unaligned.apk
|
||||
$(ZIPALIGN) -f -v 4 gecko-unaligned.apk $@
|
||||
|
91
embedding/android/Restarter.java.in
Normal file
91
embedding/android/Restarter.java.in
Normal file
@ -0,0 +1,91 @@
|
||||
/* -*- Mode: Java; tab-width: 20; indent-tabs-mode: nil; -*-
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Android code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Brad Lassey <blassey@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#filter substitution
|
||||
package org.mozilla.@MOZ_APP_NAME@;
|
||||
|
||||
import android.content.*;
|
||||
import android.util.Log;
|
||||
import java.io.*;
|
||||
|
||||
public class Restarter extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
Log.i("Restarter", "trying to restart @MOZ_APP_NAME@");
|
||||
try {
|
||||
boolean stillRunning;
|
||||
do {
|
||||
stillRunning = false;
|
||||
Process p = Runtime.getRuntime().exec("/system/bin/ps");
|
||||
BufferedReader psOut = new BufferedReader(new InputStreamReader(p.getInputStream()));
|
||||
String line;
|
||||
Log.i("Restarter", "pid: " + new Integer(android.os.Process.myPid()).toString());
|
||||
while((line = psOut.readLine()) != null) {
|
||||
Log.i("Restarter", "ps: " + line);
|
||||
if (line.contains("org.mozilla.@MOZ_APP_NAME@.App")){
|
||||
if (!line.contains(new Integer(android.os.Process.myPid()).toString())){
|
||||
Log.i("Restarter", "app still running, wait a bit");
|
||||
stillRunning = true;
|
||||
Thread.sleep(500);
|
||||
break; // don't need to look at the rest
|
||||
} else {
|
||||
Log.i("Restarter", "found ourselves");
|
||||
}
|
||||
}
|
||||
}
|
||||
} while(stillRunning);
|
||||
} catch (Exception e) {
|
||||
Log.i("Restarter", e.toString());
|
||||
}
|
||||
try {
|
||||
String action = "android.intent.action.MAIN";
|
||||
String env;
|
||||
StringBuffer envstr = new StringBuffer();
|
||||
for (int c = 0; (env = intent.getStringExtra("env" + c)) != null; c++) {
|
||||
envstr.append(" --es env" + c + " " + env);
|
||||
}
|
||||
String amCmd = "/system/bin/am start -a " + action + envstr.toString() +
|
||||
" -n org.mozilla.@MOZ_APP_NAME@/org.mozilla.@MOZ_APP_NAME@.App";
|
||||
Log.i("Restarter", amCmd);
|
||||
|
||||
Runtime.getRuntime().exec(amCmd);
|
||||
} catch (Exception e) {
|
||||
Log.i("Restarter", e.toString());
|
||||
}
|
||||
System.exit(0);
|
||||
}
|
||||
};
|
Loading…
Reference in New Issue
Block a user