Build widget sample using gradle. (Drop support for original Google TV.)
This commit is contained in:
parent
5930d674a2
commit
2877ebd7ce
1
examples/widget/.gitignore
vendored
Normal file
1
examples/widget/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/build
|
@ -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
|
@ -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
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
28
examples/widget/build.gradle
Normal file
28
examples/widget/build.gradle
Normal 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')
|
||||
}
|
@ -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>
|
@ -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 *;
|
||||
#}
|
@ -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
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -2,3 +2,4 @@ include ':emulatorview'
|
||||
include ':term'
|
||||
include ':examples:intents'
|
||||
include ':examples:pathbroadcasts'
|
||||
include ':examples:widget'
|
||||
|
Loading…
Reference in New Issue
Block a user