package jackpal.androidterm.sample.telnet;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
/**
* Provides a UI to launch the terminal emulator activity, connected to
* either a local shell or a Telnet server.
*/
public class LaunchActivity extends Activity
{
private static final String TAG = "TelnetLaunchActivity";
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.launch_activity);
final Context context = this;
addClickListener(R.id.launchLocal, new OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent(context, TermActivity.class);
intent.putExtra("type", "local");
startActivity(intent);
}});
final EditText hostEdit = (EditText) findViewById(R.id.hostname);
addClickListener(R.id.launchTelnet, new OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent(context, TermActivity.class);
intent.putExtra("type", "telnet");
String hostname = hostEdit.getText().toString();
intent.putExtra("host", hostname);
startActivity(intent);
}});
// Unpack the binary executable if not already done
setupBinDir();
}
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();
}
}