Build widget sample using gradle. (Drop support for original Google TV.)

This commit is contained in:
Jack Palevich 2015-02-14 10:24:49 -08:00
parent 5930d674a2
commit 2877ebd7ce
16 changed files with 30 additions and 446 deletions

1
examples/widget/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

View File

@ -1,47 +0,0 @@
bindir = assets
srcdir = assets-src
bin = $(bindir)/execpty-$(ARCH)
NDK = $(shell dirname `which ndk-build`)
ifeq ($(NDK),)
check-ndk = ndk-not-found
else
check-ndk =
endif
ifeq ($(ARCH),mips)
TOOLCHAIN_DIR = $(NDK)/toolchains/mipsel-*/prebuilt/*/bin
endif
TOOLCHAIN_DIR ?= $(NDK)/toolchains/$(ARCH)-*/prebuilt/*/bin
CC = $(firstword $(shell echo $(TOOLCHAIN_DIR)/*-gcc))
STRIP = $(firstword $(shell echo $(TOOLCHAIN_DIR)/*-strip))
ifeq ($(ARCH),arm)
SYSROOT = $(NDK)/platforms/android-3/arch-arm
endif
SYSROOT ?= $(NDK)/platforms/android-9/arch-$(ARCH)
all: $(check-ndk) arm x86 mips
arm: $(check-ndk)
@$(MAKE) ARCH=arm _do_build
x86: $(check-ndk)
@$(MAKE) ARCH=x86 _do_build
mips: $(check-ndk)
@$(MAKE) ARCH=mips _do_build
ndk-not-found:
$(error Android NDK not found. Make sure ndk-build is in your PATH)
_do_build: make_bindir $(bin)
make_bindir:
mkdir -p $(bindir)
$(bindir)/%-$(ARCH) : $(srcdir)/%.c
$(CC) --sysroot=$(SYSROOT) -static -o $@ $<
$(STRIP) $@
clean:
rm -f $(bindir)/*
.PHONY: clean make_bindir _do_build ndk-not-found arm x86 mips all

View File

@ -1,15 +0,0 @@
This example requires a few manual build steps.
# Build the regular Android Terminal Emulator
cd path-AndroidTerminalEmulator-root-directory
tools/update.sh
tools/build-debug
# Build and install the widget.
cd examples/widget
export PATH=path-to-ndk:$PATH
make
ant debug
adb install -r bin/LaunchActivity-debug.apk

View File

@ -1,17 +0,0 @@
# This file is used to override default values used by the Ant build system.
#
# This file must be checked into Version Control Systems, as it is
# integral to the build system of your project.
# This file is only used by the Ant script.
# You can use this to override default values such as
# 'source.dir' for the location of your java source folder and
# 'out.dir' for the location of your output folder.
# You can also use it define how the release builds are signed by declaring
# the following properties:
# 'key.store' for the location of your keystore and
# 'key.alias' for the name of the key to use.
# The password will be asked during the build when you use the 'release' target.

View File

@ -1,235 +0,0 @@
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/select.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <errno.h>
#define BUFSIZE 4096
char buf[BUFSIZE];
pid_t pid;
static void do_copy(int dst, int src);
static int do_exec(char **argv, char **envp);
/**
* Example of how to obtain a pty and connect a process to it using C and the
* POSIX API.
*
* Traditionally, a tty device is an actual piece of hardware such as a serial
* port. You would connect a physical VT100 terminal (other models of terminal
* are available) to the serial port, and your program would interact with the
* terminal by reading and writing to the tty device.
*
* When emulating a terminal in software, we ask the kernel to create a
* "pseudoterminal" (pty) device for us. How exactly this is done has varied
* over the decades, but these days, we open /dev/ptmx (the "master" device),
* which causes the kernel to create a new ("slave") pty under /dev/pts. The
* program running in the terminal will do I/O to the slave pty, but instead of
* sending the data to hardware, the kernel will pass it to us over the file
* descriptor we got when we opened the master device. See do_exec() for
* details of how to do this.
*
* In addition, this program passes data between TermSession in the Java
* process and the tty via its standard input/output. You may choose instead
* to place the code to obtain the pty and create the process in a native
* method (JNI library) and invoke it from Java. In that case, you will
* instead need to make a java.io.FileDescriptor object holding the master
* device's file descriptor in the VM and return that object from your native
* method.
*/
int main(int argc, char **argv, char **envp) {
int stdin_fd = 0, stdout_fd = 1, ptmx_fd;
fd_set readfds;
if (argc < 2) {
fprintf(stderr, "execpty: no arguments given\r\n");
return 1;
}
/* Create the pty and run the target program using it */
if ((ptmx_fd = do_exec(argv+1, envp)) == -1) {
return 1;
}
/**
* Loop waiting for either the master device or standard input to
* become readable, and copy data (from the master device to standard
* output, or from standard input to the master device) as needed.
*
* See the documentation for select(2) for details.
*/
FD_SET(stdin_fd, &readfds);
FD_SET(ptmx_fd, &readfds);
while (select(ptmx_fd+1, &readfds, NULL, NULL, NULL) >= 0) {
if (FD_ISSET(stdin_fd, &readfds)) {
do_copy(ptmx_fd, stdin_fd);
}
if (FD_ISSET(ptmx_fd, &readfds)) {
do_copy(stdout_fd, ptmx_fd);
}
FD_ZERO(&readfds);
FD_SET(stdin_fd, &readfds);
FD_SET(ptmx_fd, &readfds);
}
/* We only get here if select() errors out */
perror("execpty: select() failed:");
return 1;
}
/**
* Open the master device, obtain a slave pty, create a new process, connect
* it to the slave pty, and exec the program specified by argv[0] with
* arguments argv[][] and environment envp[][]. Returns the file descriptor
* number of the master device.
*/
static int do_exec(char **argv, char **envp) {
int ptmx_fd;
char *slave_pty;
/* Open the master device. */
ptmx_fd = open("/dev/ptmx", O_RDWR);
/**
* Obtain permissions on the slave pty and unlock it for use. See
* grantpt(2) and unlockpt(2) documentation for details.
*
* PS: On a Linux system with Unix98 ptys (/dev/pts) such as any
* Android device, grantpt() is actually a no-op, but POSIX says we
* should make these system calls in this order.
*
* PPS: Since grantpt() is a no-op, the requirement to unlock the slave
* pty is the only thing stopping us from doing this entirely in Java.
* (A tiny Linux kernel patch would lift that requirement, but would be
* highly unlikely to ever be accepted.)
*/
if (grantpt(ptmx_fd) || unlockpt(ptmx_fd)) {
return -1;
}
/* Get the path to the slave pty device. See ptsname(2) documentation
for details. */
slave_pty = ptsname(ptmx_fd);
/* Create a child process (which will initially be a clone of the
parent process). See fork(2) documentation for details. */
if ((pid = fork()) == -1) {
perror("execpty: fork() failed:");
return -1;
}
if (pid == 0) {
/* fork() returning 0 says that we are the child process. */
int fd;
/* Close the master device fd, as we won't need it. */
close(ptmx_fd);
/**
* Become process group leader and session leader. Exactly
* what this does is somewhat arcane, but the result is
* important for job control in the shell. Many shells will
* do this if we don't take care of it for them.
*
* See setsid(2) documentation and the definitions of
* "session", "session leader", "process group", "process group
* leader" and "controlling terminal" in the POSIX standard if
* you really want to understand what this does.
*/
setsid();
/**
* Open the slave pty and use the resulting file descriptor as
* standard input, output, and error.
*
* Because the slave pty is a terminal device, and one of
* setsid()'s effects is to detach the calling process from any
* controlling terminal, we will pick up the slave pty as our
* controlling terminal when we open it. See the documentation
* for open(2), particularly the flag O_NOCTTY, for details.
*
* Normally, we'd open two descriptors, one for reading only
* for standard input, and one for writing only for standard
* output/error. But the Android shell tries to write its
* prompt to standard input (probably a bug), so we need
* stdin to be open for both reading and writing.
*/
if ((fd = open(slave_pty, O_RDWR)) == -1) {
exit(1);
}
dup2(fd, 0);
dup2(fd, 1);
dup2(fd, 2);
close(fd);
/**
* Try to start the target program with the provided arguments
* and environment variables, and exit (the child process) if
* it fails.
*/
if (execve(argv[0], argv, envp)) {
exit(1);
}
}
/* Only the parent process will run this code. */
return ptmx_fd;
}
/**
* Copy as much data as we can read from the src fd without blocking (up to
* BUFSIZE bytes) to the dst fd.
*/
static void do_copy(int dst, int src) {
int count, saved_errno = 0, status;
memset(buf, 0, BUFSIZE);
count = read(src, buf, BUFSIZE);
switch (count) {
case -1:
saved_errno = errno;
if (saved_errno != EIO) {
fprintf(stderr, "execpty: read(%d, ...) failed: %s\r\n",
src, strerror(saved_errno));
exit(1);
}
/* EIO: process exited? fall through */
case 0:
if (waitpid(pid, &status, WNOHANG) == 0) {
/* process didn't exit? */
if (saved_errno > 0) {
fprintf(stderr,
"execpty: read(%d, ...) failed: %s\r\n",
src, strerror(saved_errno));
exit(1);
} else {
break;
}
}
/* EOF (process exited) */
if (WIFEXITED(status)) {
printf("Process exited with status %d\r\n",
WEXITSTATUS(status));
exit(0);
} else if (WIFSIGNALED(status)) {
printf("Process killed by signal %d\r\n",
WTERMSIG(status));
exit(0);
}
break;
default:
write(dst, buf, count);
break;
}
}

View File

@ -0,0 +1,28 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 11
buildToolsVersion "21.1.2"
defaultConfig {
applicationId "jackpal.androidterm.sample.telnet"
minSdkVersion 3
targetSdkVersion 11
ndk {
moduleName "libjackpal-androidterm4"
ldLibs "log"
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
}
}
dependencies {
compile project(':emulatorview')
}

View File

@ -1,13 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project>
<!-- Additional targets for the ant-driven Android project build -->
<target name="-pre-build">
<!-- Build the execpty binary via the makefile -->
<exec executable="make" searchpath="true" />
</target>
<target name="-pre-clean">
<exec executable="make" searchpath="true">
<arg value="clean" />
</exec>
</target>
</project>

View File

@ -1,20 +0,0 @@
# To enable ProGuard in your project, edit project.properties
# to define the proguard.config property as described in that file.
#
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in ${sdk.dir}/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the ProGuard
# include property in project.properties.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

View File

@ -1,15 +0,0 @@
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system edit
# "ant.properties", and override values to adapt the script to your
# project structure.
#
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
# Project target.
target=android-11
android.library.reference.1=../../libraries/emulatorview

View File

@ -56,88 +56,4 @@ public class LaunchActivity extends Activity
private void addClickListener(int buttonId, OnClickListener onClickListener) {
((Button) findViewById(buttonId)).setOnClickListener(onClickListener);
}
/**
* Stuff to grab the 'execpty' binary for this architecture and unpack it
* into bin/ under our data directory. See TermActivity to see how we use
* this program.
*/
static String getDataDir(Context context) {
/* On API 4 and later, you can just do this */
// return context.getApplicationInfo().dataDir;
String packageName = context.getPackageName();
PackageManager pm = context.getPackageManager();
String dataDir = null;
try {
dataDir = pm.getApplicationInfo(packageName, 0).dataDir;
} catch (Exception e) {
// Won't happen -- we know we're installed
}
return dataDir;
}
private void setupBinDir() {
String dataDir = getDataDir(this);
File binDir = new File(dataDir, "bin");
if (!binDir.exists()) {
try {
binDir.mkdir();
chmod("755", binDir.getAbsolutePath());
} catch (Exception e) {
}
}
/**
* NB: If you actually plan on deploying an app which ships a binary
* this way, you will want to implement versioning of the binary so
* that you aren't writing it out every time the app is run.
*/
File binary = new File(binDir, "execpty");
String arch = getArch();
try {
InputStream src = getAssets().open("execpty-" + arch);
FileOutputStream dst = new FileOutputStream(binary);
copyStream(dst, src);
chmod("755", binary.getAbsolutePath());
} catch (Exception e) {
}
}
private String getArch() {
/* Returns the value of uname -m */
String machine = System.getProperty("os.arch");
Log.d(TAG, "os.arch is " + machine);
/* Convert machine name to our arch identifier */
if (machine.matches("armv[0-9]+(tej?)?l")) {
return "arm";
} else if (machine.matches("i[3456]86")) {
return "x86";
} else if (machine.equals("OS_ARCH")) {
/* This is what API < 5 devices seem to return. Presumably all
of these are ARM devices. */
return "arm";
} else {
/* Result is correct for mips, and this is probably the best thing
to do for an unknown arch */
return machine;
}
}
private void copyStream(OutputStream dst, InputStream src) throws IOException {
byte[] buffer = new byte[4096];
int bytesRead = 0;
while ((bytesRead = src.read(buffer)) >= 0) {
dst.write(buffer, 0, bytesRead);
}
dst.close();
}
private void chmod(String... args) throws IOException {
String[] cmdline = new String[args.length + 1];
cmdline[0] = "/system/bin/chmod";
System.arraycopy(args, 0, cmdline, 1, args.length);
new ProcessBuilder(cmdline).start();
}
}

View File

@ -2,3 +2,4 @@ include ':emulatorview'
include ':term'
include ':examples:intents'
include ':examples:pathbroadcasts'
include ':examples:widget'