// Copyright 2012 Georg-August-Universität Göttingen, Germany // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. 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 java.util.ArrayList; import java.util.List; import org.xmlpull.v1.XmlSerializer; import android.util.Log; import android.util.Xml; import android.view.View; import android.view.ViewGroup; /** *
* TODO comment *
* * @author Florian Unger * @version 1.0 */ public class AndroidMonitorLogFile { /** ** Name of the log file which is stored in the internal space of the device. *
*/ private String name; /** ** File representation to store monitored information. *
*/ private File file; /** ** List representing all components which was written to log file before. *
*/ private List* Constructor. Creates a new AndroidmonitorLogFile. *
* * @param appName * Name of the calling application. * @param dir * Folder to store the log file. */ public AndroidMonitorLogFile(String appName, File dir) { currentLoggedComponents = new ArrayList* Get file name which is in use. *
* * @return filename */ public String getFileName() { return this.name; } /** * ** Writes information about the application to the log file. *
* */ private void setAppInformation() { // TODO create app information in the same manner as coded in // getDeviceInformation } /** ** Query device information and store it to log file. *
* */ private void setDeviceInformation() { 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(); 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()); } } /** ** 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(); 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" serializer.startTag("", "ancestors"); Class extends Object> classobject = view.getClass(); while((classobject != null)){ serializer.startTag("", "ancestor"); serializer.attribute("", "name", classobject.getName()); serializer.endTag("", "ancestor"); classobject = classobject.getSuperclass(); } serializer.endTag("", "ancestors"); 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 hash * hash value of the calling view of the listener * @param type * the type of listener e.g. textView ... * @param message * message typed in */ public void addEvent(int hash, String type, String message){ 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", "" + hash); serializer.attribute("", "name", "source"); serializer.endTag("", "param"); serializer.startTag("", "param"); serializer.attribute("", "value", message); serializer.attribute("", "name", "message"); 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()); } } /** ** 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; } } /** * ** Check whether a component is still written to log file. *
* * @param hashCode * hash code of the view * @return */ public Boolean isComponentLogged(Integer hashCode){ return currentLoggedComponents.contains(hashCode); } }