android:deploy
and android:undeploy
goals.To get the full benefit of these features in Eclipse we need
m2e
integration. Luckily, the m2e-android project is making good progress.Good stuff.
android:deploy
and android:undeploy
goals.m2e
integration. Luckily, the m2e-android project is making good progress.
[jjohnson@jjohnson 20110613]$ cp ~/.m2/repository/commons-lang/commons-lang/2.4/commons-lang-2.4.jar .
[jjohnson@jjohnson 20110613]$ dx --dex --output=test.apk commons-lang-2.4.jar
[jjohnson@jjohnson 20110613]$ dexdump -d -l xml test.apk
<api>
<package name="org.apache.commons.lang"
>
<class name="ArrayUtils"
extends="java.lang.Object"
abstract="false"
static="false"
final="false"
visibility="public"
>
...
C:\Documents and Settings\Jeremiah Johnson\20110613>copy ..\.m2\repository\commons-lang\commons-lang\2.4\commons-lang-2.4.jar .
C:\Documents and Settings\Jeremiah Johnson\20110613>dx --dex --output=test.apk commons-lang-2.4.jar
UNEXPECTED TOP-LEVEL EXCEPTION:
java.io.FileNotFoundException: commons-lang-2.4.jar (The system cannot find the file specified)
at java.util.zip.ZipFile.open(Native Method)
at java.util.zip.ZipFile.(ZipFile.java:127)
at java.util.zip.ZipFile.(ZipFile.java:144)
at com.android.dx.cf.direct.ClassPathOpener.processArchive(ClassPathOpener.java:205)
at com.android.dx.cf.direct.ClassPathOpener.processOne(ClassPathOpener.java:130)
at com.android.dx.cf.direct.ClassPathOpener.process(ClassPathOpener.java:108)
at com.android.dx.command.dexer.Main.processOne(Main.java:313)
at com.android.dx.command.dexer.Main.processAllFiles(Main.java:233)
at com.android.dx.command.dexer.Main.run(Main.java:185)
at com.android.dx.command.dexer.Main.main(Main.java:166)
at com.android.dx.command.Main.main(Main.java:90)
1 error; aborting
C:\Documents and Settings\Jeremiah Johnson\20110613>dx --dex --output="C:\Documents and Settings\Jeremiah Johnson\20110613\test.apk" "C:\Documents and Settings\Jeremiah Johnson\20110613\commons-lang-2.4.jar"
and was unexpected at this time.
C:\Documents and Settings\Jeremiah Johnson\20110613>cd ..
C:\Documents and Settings\Jeremiah Johnson>move 20110613 C:\
C:\Documents and Settings\Jeremiah Johnson>cd C:\20110613
C:\20110613>dx --dex --output=C:\20110613\test.apk C:\20110613\commons-lang-2.4.
jar
C:\20110613>dexdump -d -l xml test.apk
E/dalvikvm( 3152): sysMapFileSegmentInShmem not implemented.
W/dalvikvm( 3152): Zip: cd map failed
Unable to open 'test.apk' as zip archive
Not Zip, retrying as DEX
E/dalvikvm( 3152): ERROR: Bad magic number (0x50 4b 03 04)
ERROR: Failed structural verification of 'test.apk'
C:\20110613>dexdump -d -l xml C:\20110613\test.apk
E/dalvikvm( 1740): sysMapFileSegmentInShmem not implemented.
W/dalvikvm( 1740): Zip: cd map failed
Unable to open 'C:\20110613\test.apk' as zip archive
Not Zip, retrying as DEX
E/dalvikvm( 1740): ERROR: Bad magic number (0x50 4b 03 04)
ERROR: Failed structural verification of 'C:\20110613\test.apk'
// start the Web server for config and maintenance
webServer = new Server(8080);
try {
WebAppContext webapp = new WebAppContext();
webapp.setConfigurationClasses(new String[] { DexWebInfConfiguration.class.getName(),
JettyWebXmlConfiguration.class.getName(), WebXmlConfiguration.class.getName() });
webapp.setContextPath("/");
webapp.setTempDirectory(new File("/sdcard/TGP-work/"));
webapp.setWar("/sdcard/TGP-webapps/TGP-ROOT.war");
webServer.setHandler(webapp);
}
catch (Exception e) {
Log.d(LOG_TAG, "unexpected exception setting temp: " + e);
}
/**
* Adds dex support to the classloader used in the Jetty WebInfConfiguration.
*
* <code>webapp.setConfigurationClasses(new String[] { DexWebInfConfiguration.class.getName() });</code>
*/
public class DexWebInfConfiguration extends WebInfConfiguration {
public void preConfigure(WebAppContext context) throws Exception {
context.setClassLoader(new DexClassLoader(context.getTempDirectory().getCanonicalPath()
+ "/webapp/WEB-INF/lib/classes.zip", context.getTempDirectory().getCanonicalPath(), null, getClass()
.getClassLoader()));
super.preConfigure(context);
}
}
dex
on all of the compiled code in the WAR (i.e. the JSPs as well as the regular servlets).jetty-jspc-maven-plugin
docs and the second from i-Jetty.
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-jspc-maven-plugin</artifactId>
<version>7.3.0.v20110203</version>
<executions>
<execution>
<id>jspc</id>
<goals>
<goal>jspc</goal>
</goals>
<configuration>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<!-- use web.xml from jspc rather than src version -->
<webXml>${project.build.directory}/web.xml</webXml>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.1</version>
<executions>
<execution>
<id>generate-dex</id>
<phase>process-classes</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>${android.home}/platform-tools/dx</executable>
<arguments>
<argument>--dex</argument>
<argument>--verbose</argument>
<argument>--core-library</argument>
<argument>--output=${project.build.directory}/classes.dex</argument>
<argument>--positions=lines</argument>
<argument>${project.build.directory}/classes/</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>copydex</id>
<phase>process-classes</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<mkdir
dir="${project.build.directory}/${project.artifactId}-${project.version}/WEB-INF/lib" />
<jar basedir="${project.build.directory}" update="true"
includes="classes.dex"
destfile="${project.build.directory}/${project.artifactId}-${project.version}/WEB-INF/lib/classes.zip" />
</tasks>
</configuration>
</execution>
</executions>
</plugin>
// start the Web server for config and maintenance
webServer = new Server(8080);
try {
HandlerCollection handlers = new HandlerCollection();
ContextHandlerCollection contexts = new ContextHandlerCollection();
handlers.setHandlers(new Handler[] { contexts, new DefaultHandler() });
webServer.setHandler(handlers);
DeploymentManager deployer = new DeploymentManager();
deployer.setContexts(contexts);
webServer.addBean(deployer);
WebAppProvider webAppProvider = new WebAppProvider();
webAppProvider.setConfigurationClasses(new String[] { DexWebInfConfiguration.class.getName(),
JettyWebXmlConfiguration.class.getName(), WebXmlConfiguration.class.getName() });
webAppProvider.setExtractWars(true);
webAppProvider.setScanInterval(10);
webAppProvider.setMonitoredDirName("/sdcard/jetty/webapps/");
deployer.addAppProvider(webAppProvider);
}
catch (Exception e) {
Log.d(LOG_TAG, "unexpected exception setting temp: " + e);
}
try {
webServer.start();
Log.d(LOG_TAG, "started Web server @ " + getPublicInetAddress());
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = new Notification( R.drawable.web_server_icon, "WebServer", System.currentTimeMillis());
notification.flags |= Notification.FLAG_ONGOING_EVENT; // Notification.FLAG_NO_CLEAR;
Intent notificationIntent = new Intent(this, MyApp.class);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(getApplicationContext(), "Web Server" , "Web Server Listening @ " + getPublicInetAddress(), contentIntent);
notificationManager.notify(NOTIFICATION_ID_WEB_SERVER, notification);
}
catch (Exception e) {
Log.d(LOG_TAG, "unexpected exception starting Web server: " + e);
}
/**
* Adds dex support to the classloader used in the Jetty WebInfConfiguration.
*
*webapp.setConfigurationClasses(new String[] { DexWebInfConfiguration.class.getName() });
*/
public class DexWebInfConfiguration extends WebInfConfiguration {
/**
* The parent preConfigure is going to load the JAR and class files in so we
* need to adjust the class loader before
*/
@Override
public void preConfigure(WebAppContext context) throws Exception {
String tempDir = getCanonicalNameForWebAppTmpDir(context);
if (tempDir != null) {
tempDir = Environment.getExternalStorageDirectory() + "/" + tempDir;
String dexZip = tempDir + "/webapp/WEB-INF/lib/classes.zip";
context.setClassLoader(new DexClassLoader(dexZip, tempDir, null, getClass().getClassLoader()));
Log.d("Jetty", "Added DexClassLoader for " + dexZip);
}
super.preConfigure(context);
}
}
jetty.jar
. For example, here's a little shell script I used for my WAR Deployed Web App.
jar xf ../jetty-continuation-*.jar
jar xf ../jetty-http-*.jar
jar xf ../jetty-io-*.jar
jar xf ../jetty-security-*.jar
jar xf ../jetty-server-*.jar
jar xf ../jetty-servlet-*.jar
jar xf ../jetty-util-*.jar
jar xf ../jetty-webapp-*.jar
jar xf ../jetty-xml-*.jar
jar xf ../servlet-api-2.5.jar
jar cf ~/Documents/ECLIPSE_PROJECT_PATH/libs/jetty.jar *
// work-around for Android defect 9431
System.setProperty("java.net.preferIPv4Stack", "true");
System.setProperty("java.net.preferIPv6Addresses", "false");
http://localhost:8080/
but from my G1 I'd point at http://10.1.1.8:8080/
(of couse, this IP is local to my LAN).
adb -e forward tcp:8080 tcp:8080
onCreate
webServer = new Server(8080);
Handler handler = new AbstractHandler() {
public void handle(String target, Request request, HttpServletRequest servletRequest,
HttpServletResponse servletResponse) throws IOException, ServletException {
servletResponse.setContentType("text/html");
servletResponse.setStatus(HttpServletResponse.SC_OK);
servletResponse.getWriter().println("<h1>Hello World</h1>");
((Request) request).setHandled(true);
}
};
webServer.setHandler(handler);
try {
webServer.start();
Log.d(LOG_TAG, "started Web server @ " + getPublicInetAddress());
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = new Notification( R.drawable.web_server_icon, "WebServer", System.currentTimeMillis());
notification.flags |= Notification.FLAG_ONGOING_EVENT; // Notification.FLAG_NO_CLEAR;
Intent notificationIntent = new Intent(this, MyApp.class);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(getApplicationContext(), "Web Server" , "Web Server Listening @ " + getPublicInetAddress(), contentIntent);
notificationManager.notify(NOTIFICATION_ID_WEB_SERVER, notification);
}
catch (Exception e) {
Log.d(LOG_TAG, "unexpected exception starting Web server: " + e);
}
webServer = new Server(8080);
WebAppContext webapp = new WebAppContext();
webapp.setContextPath("/");
webapp.setTempDirectory(new File("/sdcard/my-work/"));
webapp.setWar("/sdcard/my-webapps/my-ROOT.war");
webServer.setHandler(webapp);
try {
webServer.start();
Log.d(LOG_TAG, "started Web server @ " + getPublicInetAddress());
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = new Notification( R.drawable.web_server_icon, "WebServer", System.currentTimeMillis());
notification.flags |= Notification.FLAG_ONGOING_EVENT; // Notification.FLAG_NO_CLEAR;
Intent notificationIntent = new Intent(this, MyApp.class);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(getApplicationContext(), "Web Server" , "Web Server Listening @ " + getPublicInetAddress(), contentIntent);
notificationManager.notify(NOTIFICATION_ID_WEB_SERVER, notification);
}
catch (Exception e) {
Log.d(LOG_TAG, "unexpected exception starting Web server: " + e);
}
my-work
directory gets created fine. I need to push the WAR file out: for the emulator I used adb push ../my-ROOT.war sdcard/my-webapps
try / catch
around the XmlParser validation feature that is causing trouble so we can use more recent versions.
$ svn diff -c 2770 XmlParser.java
Index: XmlParser.java
===================================================================
--- XmlParser.java (revision 2769)
+++ XmlParser.java (revision 2770)
@@ -107,6 +107,7 @@
_parser.getXMLReader().setFeature("http://xml.org/sax/features/validation", validating);
_parser.getXMLReader().setFeature("http://xml.org/sax/features/namespaces", true);
_parser.getXMLReader().setFeature("http://xml.org/sax/features/namespace-prefixes", false);
+ _parser.getXMLReader().setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", validating);
}
catch (Exception e)
{
Eclipse -> Preferences... | General -> Network Connections
adb forward tcp:8080 tcp:8080
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --proxy-server=localhost:8080
click
event but I noticed a delay in the iPad so I switched over to the touchstart
event. When the application is running in iPad / iPhone, the whole canvas is draggable and looks crappy.onClick
is intentional in iPhone / iPad because the browser (UIWebView, in this case) is waiting to see if there is going to be a gesture. That makes sense to me so any cases where I had a .click
I changed to a .bind(clickevent
. I set clickevent = click
by default but override with clickevent = touchstart
when on iPhone / iPad.event.preventDefault
the view can no longer be dragged down.
$ git diff HTML/main.js
diff --git a/HTML/main.js b/HTML/main.js
index 4e7661b..5bceab2 100644
--- a/HTML/main.js
+++ b/HTML/main.js
@@ -23,6 +23,14 @@ if(window.Touch) {
clickevent = 'touchstart';
}
+// TODO - can combine with other iPad / iPhone checks but keeping separate
+// for now just to make it stand out
+if(window.Touch) {
+ document.ontouchmove = function(event) {
+ event.preventDefault();
+ }
+}
+
$.ajaxSetup({
beforeSend: function(xhr) { xhr.setRequestHeader("Emsauthtoken",localStorag
cache: false,
At one time you could have said Apple was late since Palm already had the Smart Phone market cornered.
$ curl --include http://webkit.org/demos/sticky-notes/StickyNotes.manifest
HTTP/1.1 200 OK
Date: Thu, 11 Mar 2010 06:01:37 GMT
Server: Apache/2.2.14 (Unix) mod_ssl/2.2.14 OpenSSL/0.9.8l DAV/2 mod_python/3.3.1 Python/2.5.4
Last-Modified: Sat, 13 Jun 2009 00:53:08 GMT
ETag: "38-46c303f980500"
Accept-Ranges: bytes
Content-Length: 56
Content-Type: text/cache-manifest
CACHE MANIFEST
deleteButton.png
deleteButtonPressed.png
As a side note - I've read that Windows people would see the Windows logo in this domain and Mac people would see the Apple logo. What do you see? http://i♥.com/.
I have a uMMC unit that I successfully upgraded to firmware
102.08-b004 so that I could use the Arduino libraries.
The commands to changing and reading the settings work and the version
command works but Z always returns E05. I've tried 3 different cards
that all worked before upgrading from 101.56 and now they all fail to
initialize. I've tried different baud rates (9600 to 115200) but they
all fail. Does this device support 102.08? Is there anything else I
can do to trouble-shoot this? The Arduino library page says that I
can use 101.56 but the code says I have to have 102.01 at minimum -
which is it? Could you point me at 102.07 so I can try that version?
#include "NewSoftSerial.h"
#include "RogueSD.h"
#define COM_BAUD_RATE 115200
#define DATA_LOGGER_BAUD_RATE 9600
#define DATA_LOGGER_FILENAME "/uMMCtest.csv"
#define DATA_LOGGER_RX_PIN 3 // ATmega168 pin 5
#define DATA_LOGGER_TX_PIN 4 // ATmega168 pin 6
// using hardware serial interface for cli communications
static HardwareSerial& comSerial = Serial;
// static NewSoftSerial comSerial(DATA_LOGGER_TX_PIN, DATA_LOGGER_RX_PIN);
// the file handle used for logging; will be > 0 if uMMC present
static int dataLoggerFileHandle = -1;
// The firmware assumes the uMMC API for the data logger.
static NewSoftSerial dataLoggerSerial(DATA_LOGGER_TX_PIN, DATA_LOGGER_RX_PIN);
// static HardwareSerial& dataLoggerSerial = Serial;
static RogueSD ummc(dataLoggerSerial);
void setup() {
comSerial.begin(COM_BAUD_RATE);
comSerial.println("uMMC Test Booting...");
dataLoggerSerial.begin(DATA_LOGGER_BAUD_RATE);
comSerial.print("uMMC Version: ");
comSerial.println(ummc.version());
ummc.sync();
dataLoggerFileHandle = ummc.open(DATA_LOGGER_FILENAME, OPEN_APPEND);
if((dataLoggerFileHandle <= 0) || (ummc.LastErrorCode != 0)) {
comSerial.print("uMMC Error: ");
comSerial.println(ummc.LastErrorCode, HEX);
}
}
void loop() {
if(millis() > 20000) {
if(dataLoggerFileHandle > 0) {
ummc.close(dataLoggerFileHandle);
dataLoggerFileHandle = -1;
comSerial.println("Closed Data Logger");
}
} else {
writeToDataLogger();
}
delay(4000);
}
void writeToDataLogger() {
if(dataLoggerFileHandle <= 0) {
return;
}
int chamberPressure = millis() >> 8;
int tankPressure = millis() >> 8;
unsigned long dataLoggerStartTime = micros();
ummc.writeln_prep(dataLoggerFileHandle);
ummc.print(millis(), HEX);
ummc.print(",");
ummc.print(chamberPressure, HEX);
ummc.print(",");
ummc.print(tankPressure, HEX);
ummc.print("\n");
ummc.writeln_finish();
if((dataLoggerFileHandle <= 0) || (ummc.LastErrorCode != 0)) {
comSerial.print("uMMC Error: ");
comSerial.println(ummc.LastErrorCode, HEX);
}
comSerial.print("Micros: ");
comSerial.println(micros() - dataLoggerStartTime);
}
void setup() {
Serial.begin(BAUD_RATE);
Serial.println("FTH-Arduino Booting...");
...
// Read the transducers @ 1kHz
MsTimer2::set(1000, readTransducer);
MsTimer2::start();
}
void loop() {
delay(4000);
Serial.println("Boo");
...
void readTransducer() {
Serial.println("Reading Transducer.");
}
FTH-Arduino Booting...
Reading Transducer.
Reading Transducer.
Reading Transducer.
BoReading Transducer.
o
Reading Transducer.
#include
#include
#include
#include
// app uses internal oscillator, RA6 for IO
#pragma config FOSC = INTOSCIO_EC
// OSCCON = 0b01110000; should switch to 8Mhz ??
#pragma config BOR = OFF // Brown out reset
#pragma config LVP = OFF // Low voltage programming
#pragma config WDT = OFF // Watchdog timer
// use pin 11 for basic LED indicator
#define LEDPin LATCbits.LATC0
#define LEDTris TRISCbits.TRISC0
void main() {
// pre / post scalers at 1:16 / 1:2
T2CONbits.T2CKPS1 = 1;
T2CONbits.T2CKPS0 = 1;
T2CONbits.T2OUTPS3 = 0;
T2CONbits.T2OUTPS2 = 0;
T2CONbits.T2OUTPS1 = 0;
T2CONbits.T2OUTPS0 = 1;
// the period is 25ms
OpenPWM1(250);
// TODO - understand all these flags
OpenADC(ADC_FOSC_8 & ADC_RIGHT_JUST & ADC_0_TAD,
ADC_CH0 & ADC_INT_OFF & ADC_VREFPLUS_VDD & ADC_VREFMINUS_VSS,
0b1011);
SetChanADC(ADC_CH0);
LEDTris = 0; // make sure LED pin is an output pin
LEDPin = 1; // turn LED on
while(1) {
LEDPin = ~LEDPin;
Delay10KTCYx(5); // (.2s delay between reads)
ConvertADC();
while(BusyADC());
// through experimentation, I found that a 'duty cycle' between
// 18 and 81 was about right; my pot in my circuit is giving
// 0 to 4.2V so I'm multiplying by 1.2; the ReadADC returns a
// 10 bit result so dividing by 16 to put me 0 to 63
SetDCPWM1(18 + ((int) (1.2 * ReadADC()) >> 4));
}
}