/*
* Copyright 2010 Pablo Arrighi, Alex Concha, Miguel Lezama for version 1.
* Copyright 2013 Pablo Arrighi, Miguel Lezama, Kevin Mazet for version 2.
*
* This file is part of GOOL.
*
* GOOL is free software: you can redistribute it and/or modify it under the terms of the GNU
* General Public License as published by the Free Software Foundation, version 3.
*
* GOOL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License version 3 for more details.
*
* You should have received a copy of the GNU General Public License along with GOOL,
* in the file COPYING.txt. If not, see <http://www.gnu.org/licenses/>.
*/
package gool.generator.android;
import gool.Settings;
import gool.ast.core.ClassDef;
import gool.ast.core.Dependency;
import gool.generator.common.CodePrinter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang.StringUtils;
public class AndroidCodePrinter extends CodePrinter {
/**
* Provides the basic functionality to generate Android code from a list of
* GOOL classes.
*/
private static final String TEMPLATE_DIR = "gool/generator/android/templates/";
public AndroidCodePrinter(File outputDir) {
super(new AndroidGenerator(), outputDir);
}
@Override
public String getTemplateDir() {
return TEMPLATE_DIR;
}
@Override
public String getFileName(String className) {
return className + ".java";
}
@Override
public List<File> print(ClassDef pclass) throws FileNotFoundException {
/*
* As the implementation of Android necessitates that an additional file
* "Activity" be created if the class contains the main method this
* method is overridden to check for this
*/
String code = pclass.getCode();
List<File> result = new ArrayList<File>();
// file separator is just a slash in Unix
// so the second argument to File() is just the directory
// that corresponds to the package name
// the first argument is the default output directory of the platform
// so the directory name ends up being something like
// GOOLOUPTUTTARGET/pack/age
File dir = new File(getOutputDir().getAbsolutePath(),
StringUtils.replace(pclass.getPackageName(), ".",
File.separator));
// Typically the outputdir was created before, but not the package
// subdirs
dir.mkdirs();
// Create the file for the class, fill it in, close it
File classFile = new File(dir, getFileName(pclass.getName()));
PrintWriter writer = new PrintWriter(classFile);
writer.println(code);
writer.close();
/*
* This part checks whether the class contains a main method/entry point
* as well as creating the class that will be equivalent to sysOut.
*/
if (pclass.isMainClass()) { // Check if class contains main method and
// if yes create activity class as well
/**
* As standard each .java file with a main method will have a
* corresponding *Activity.java file
*/
File activityFile = new File(dir, getFileName(pclass.getName())
.replace(".java", "Activity.java"));
writer = new PrintWriter(activityFile);
String activityClassCode = processTemplate("activity.vm", pclass);
writer.println(activityClassCode);
writer.close();
// Put the generated class into the result list
result.add(activityFile);
/*
* After this it checks whether a PrintOut class has been made yet
* and if not creates it. The reason why it is done here is because
* most of the time there will only be one main class and this step
* won't be repeated Unnecessarily
*/
File printOutFile = new File(dir, "PrintOut.java");
if (!printOutFile.exists()) {
writer = new PrintWriter(printOutFile);
String printOutFileCode = processTemplate("printout.vm", pclass);
writer.println(printOutFileCode);
writer.close();
// Put the generated class into the result list
result.add(printOutFile);
}
}
// Remember that you did the generation for this one abstract GOOL class
printedClasses.add(pclass);
// Put the generated class into the result list
result.add(classFile);
// Go through the dependencies
// If they are abstract GOOL classes and have not been generated, do
// that
// And add the generated classes into the result list
for (Dependency dependency : pclass.getDependencies()) {
if (!printedClasses.contains(dependency)
&& dependency instanceof ClassDef) {
result.addAll(print((ClassDef) dependency));
}
}
return result;
}
public List<File> createAndroidProject(List<File> currentFilelist) {
File oldAndroidFolder = new File(Settings.get("android_out_dir"));
File newAndroidFolder = new File(Settings.get("android_out_dir_final"));
if (newAndroidFolder.exists()) {
deleteFolder(newAndroidFolder); // Removes all files and the
// directory as this causes problems
// for android project creation
}
File newAndroidFolderSource = new File(
Settings.get("android_out_dir_final") + "//src");
List<File> mainClassFiles = new ArrayList<File>();
populateMainMethodClasses(oldAndroidFolder, mainClassFiles);
// Below is done just to determine the package naming and main activity
// file to create a Android project
String mainMethodFolderString = mainClassFiles.get(0).getParentFile()
.getAbsolutePath(); // Get the first main method class
Settings.setAndroidMainActivity(mainClassFiles.get(0).getName()); // Sets
// this
// for
// later
// use
// by
// the
// Compiler
// class
String folderString = oldAndroidFolder.getAbsolutePath();
String packageDirectory = mainMethodFolderString
.replace(folderString, "").replace("/", ".")
.replaceFirst(".", "");
// Below ensures that the code is within a package as required by
// android, if not creates one and
// updates folders accordingly
if (packageDirectory.equals("")) {
packageDirectory = "com.test";
newAndroidFolderSource = new File(
Settings.get("android_out_dir_final") + "//src//com//test");
}
Settings.setAndroidPackage(packageDirectory);
String activityString = mainClassFiles.get(0).getName()
.replace(".java", "");
// First creates a new Android project
try {
String executeCommand = "android create project --target 1 --name AndroidProject --path "
+ newAndroidFolder.getAbsolutePath()
+ " --activity "
+ activityString + " --package " + packageDirectory;
Process waitForProcess = Runtime.getRuntime().exec(executeCommand);
try {
waitForProcess.waitFor();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// Then Copies and replaces all files from temporary directory to
// android project and deletes the old files
copyFolder(oldAndroidFolder, newAndroidFolderSource);
deleteFolder(oldAndroidFolder); // This can be commented out for
// debugging purposes
return null; // TODO return a list of all the android files in
// newAndroidFolderSource
// return value not used at present but may be needed in
// future
}
private void deleteFolder(File deleteFolder) {
String[] content;
if (deleteFolder.isDirectory()) {
content = deleteFolder.list();
for (int i = 0; i < content.length; i++) {
File myFile = new File(deleteFolder, content[i]);
if (myFile.isDirectory()) {
deleteFolder(myFile);
}
myFile.delete();
}
}
deleteFolder.delete();
}
private void copyFolder(File source, File destination) {
if (source.isDirectory()) { // Then create a new directory and
// recursively look at files inside old
// directory
if (!destination.exists()) {
destination.mkdir();
}
// All files in directory including sub directories
String files[] = source.list();
for (String file : files) {
// make new source and destination files
File newSourceFile = new File(source, file);
File newDestinationFile = new File(destination, file);
// copy recursively
copyFolder(newSourceFile, newDestinationFile);
}
}
else {// Otherwise copy the file
try {
InputStream is = new FileInputStream(source);
OutputStream os = new FileOutputStream(destination);
byte[] buf = new byte[1024];
int length;
// copy the file content in bytes
while ((length = is.read(buf)) > 0) {
os.write(buf, 0, length);
}
is.close();
os.close();
} catch (FileNotFoundException e) {
} catch (IOException ioe) {
}
}
}
/**
* Returns a list of all the classes containing main methods
*
* @param mainFolder
* @param mainClassFiles
* @return
*/
private void populateMainMethodClasses(File mainFolder,
List<File> mainClassFiles) {
File[] tempFileList = mainFolder.listFiles();
for (File tempFile : tempFileList) {
if (tempFile.isDirectory()) {
populateMainMethodClasses(tempFile, mainClassFiles);
} else {
if (tempFile.toString().endsWith("Activity.java")) {
mainClassFiles.add(tempFile);
}
}
}
}
}