package de.ugoe.cs.autoquest.androidmonitor; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.StringWriter; import org.xmlpull.v1.XmlSerializer; import android.util.Log; import android.util.Xml; import android.view.View; import android.view.ViewGroup; /** * * @author Florian Unger * @version 1.0 */ public class AndroidmonitorLogFile { // TODO rename getDeviceInformation() and getAppInformation() to set ... use // writeToFile for both private String name; private File file; public AndroidmonitorLogFile(String appName, File dir) { this.name = "android_" + appName + "_LogFile.xml"; try { // prove if file exists this.file = new File(dir, this.name); /* * if file does not exists write device and app information to a new * file. Otherwise use existing file and add activity information to * file. */ if (true) { // !this.file.exists() /* * create log file. Using method openFileOutput() does not work * for this project due to the reason that this method would try * to create the file in the directory of the non-existing * directory de.ugoe.cs.androidmonitor. This directory does not * exist due to the reason that this project is a library and * the file has to be stored in the directory of the running * application. Furthermore it would not be possible to write in * another app directory as the own one. */ // TODO split document head information from // getDeviceInformation. String string = "" + getDeviceInformation() + getAppInformation(); try { FileOutputStream outputStream = new FileOutputStream( this.file); outputStream.write(string.getBytes()); outputStream.close(); } catch (Exception e) { Log.e("this.file", "outputstream: " + e.getMessage()); } } else { // TODO add activity information } } catch (Exception e) { e.printStackTrace(); Log.e("file", "file: " + e.getMessage()); } } /** *

* Get file name which is in use. *

* * @return filename * */ public String getName() { return this.name; } // should be set private String getAppInformation() { // TODO create app information in the same manner as coded in // getDeviceInformation return ""; } /** *

* Query device information. *

* * @return XML device information in XML format */ // should be set private String getDeviceInformation() { String deviceInformation = ""; XmlSerializer serializer = Xml.newSerializer(); StringWriter writer = new StringWriter(); try { serializer.setOutput(writer); serializer.startTag("", "device"); serializer.startTag("", "param"); serializer.attribute("", "value", "" + android.os.Build.VERSION.SDK_INT); serializer.attribute("", "name", "sdk_version"); serializer.endTag("", "param"); serializer.startTag("", "param"); serializer.attribute("", "value", android.os.Build.DEVICE); serializer.attribute("", "name", "device"); serializer.endTag("", "param"); serializer.startTag("", "param"); serializer.attribute("", "value", android.os.Build.MANUFACTURER); serializer.attribute("", "name", "manufacturer"); serializer.endTag("", "param"); serializer.startTag("", "param"); serializer.attribute("", "value", android.os.Build.MODEL); serializer.attribute("", "name", "model"); serializer.endTag("", "param"); // TODO get resolution ... serializer.endTag("", "device"); serializer.endDocument(); deviceInformation = writer.toString(); } catch (IOException e) { Log.e("xml", e.getMessage()); } return deviceInformation; } /** *

* Adds some information of an component of an activity (view) to the file. *

* * @param view * view to be logged * @param parentHash * hash of the parent view * @param activityName * name of the activity that is analyzed */ public void addComponent(View view, int parentHash, String activityName) { XmlSerializer serializer = Xml.newSerializer(); StringWriter writer = new StringWriter(); // create HEX string try { serializer.setOutput(writer); serializer.startTag("", "component"); // TODO find a way in that the hash code is unique over time and // target /* * (non-Javadoc) view.getId() seems to be unique over time and * targets but there is a problem. In some cases there is no ID * (value: -1). */ serializer.attribute("", "hash", "" + view.hashCode()); serializer.startTag("", "param"); serializer.attribute("", "name", "id"); serializer.attribute("", "value", "" + view.getId()); serializer.endTag("", "param"); serializer.startTag("", "param"); serializer.attribute("", "name", "path"); serializer.attribute("", "value", activityName + "/" + getViewPath(view) + view.getClass().getSimpleName()); serializer.endTag("", "param"); serializer.startTag("", "param"); serializer.attribute("", "name", "class"); serializer.attribute("", "value", view.getClass().getName()); serializer.endTag("", "param"); serializer.startTag("", "param"); serializer.attribute("", "name", "parent"); // Problem in using view.getParent().hashCode(): // http://developer.android.com/reference/android/view/View.html#getParent() // tells: "... parent is a ViewParent and not necessarily a View." // ViewParent does not have a method hashCode(). Solution is done // add parentHash as parameter to method addComponent() and // Androidmonitor-> addLogListenerToView. serializer.attribute("", "value", "" + parentHash); serializer.endTag("", "param"); // TODO add title e.g. android:text="Button" // TODO add ancestors @see: // de.ugoe.cs.autoquest.jfcmonitor.JFCComponent#getClassHierarchy() serializer.endTag("", "component"); serializer.endDocument(); writeToFile(writer.toString()); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); Log.e("file", "outputstream: " + e.getMessage()); } catch (IllegalStateException e) { // TODO Auto-generated catch block e.printStackTrace(); Log.e("file", "outputstream: " + e.getMessage()); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); Log.e("file", "outputstream: " + e.getMessage()); } } /** *

* Add an event to the log file *

* * @param view * the calling view of the listener * @param type * the type of listener e.g. onClick ... */ public void addEvent(View view, String type) { String x = "" + view.getX(); String y = "" + view.getY(); XmlSerializer serializer = Xml.newSerializer(); StringWriter writer = new StringWriter(); try { serializer.setOutput(writer); serializer.startTag("", "event"); serializer.attribute("", "id", type); serializer.startTag("", "param"); serializer.attribute("", "value", x); serializer.attribute("", "name", "X"); serializer.endTag("", "param"); serializer.startTag("", "param"); serializer.attribute("", "value", y); serializer.attribute("", "name", "Y"); serializer.endTag("", "param"); serializer.startTag("", "param"); serializer.attribute("", "value", "" + view.hashCode()); serializer.attribute("", "name", "source"); serializer.endTag("", "param"); serializer.startTag("", "param"); serializer.attribute("", "value", "" + System.currentTimeMillis()); serializer.attribute("", "name", "timestamp"); serializer.endTag("", "param"); serializer.endTag("", "event"); serializer.endDocument(); writeToFile(writer.toString()); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); Log.e("file", "outputstream: " + e.getMessage()); } catch (IllegalStateException e) { // TODO Auto-generated catch block e.printStackTrace(); Log.e("file", "outputstream: " + e.getMessage()); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); Log.e("file", "outputstream: " + e.getMessage()); } } /** *

* Writes given information to the file. e.g. previous produced XML * statements. *

* * @param data * content to add to the file */ private void writeToFile(String data) { FileOutputStream outputStream; try { outputStream = new FileOutputStream(file, true); outputStream.write(data.getBytes()); outputStream.close(); } catch (FileNotFoundException e) { e.printStackTrace(); Log.e("file", "outputstream: " + e.getMessage()); } catch (IOException e) { e.printStackTrace(); Log.e("file", "outputstream: " + e.getMessage()); } } /** *

* Generates the path of an view element. *

* * @param view * @return path path to the element */ private String getViewPath(View view) { return getViewPath(view, null); } /** *

* Generates the path of an view element. *

* * @param view * @param path * @return path path to the element */ private String getViewPath(View view, String path) { if (path == null) { path = ""; } else { path = view.getClass().getSimpleName() + "/" + path; } if (view.getParent() != null && (view.getParent() instanceof ViewGroup)) { return getViewPath((View) view.getParent(), path); } else { return path; } } }