[1725] | 1 | package de.ugoe.cs.autoquest.androidmonitor;
|
---|
| 2 |
|
---|
| 3 | import java.io.File;
|
---|
[1728] | 4 | import java.io.FileNotFoundException;
|
---|
[1726] | 5 | import java.io.FileOutputStream;
|
---|
[1728] | 6 | import java.io.IOException;
|
---|
[1725] | 7 | import java.io.StringWriter;
|
---|
| 8 |
|
---|
| 9 | import org.xmlpull.v1.XmlSerializer;
|
---|
| 10 |
|
---|
| 11 | import android.util.Log;
|
---|
| 12 | import android.util.Xml;
|
---|
[1728] | 13 | import android.view.View;
|
---|
| 14 | import android.view.ViewGroup;
|
---|
[1725] | 15 |
|
---|
[1756] | 16 | /**
|
---|
| 17 | *
|
---|
| 18 | * @author Florian Unger
|
---|
| 19 | * @version 1.0
|
---|
| 20 | */
|
---|
[1726] | 21 | public class AndroidmonitorLogFile {
|
---|
| 22 |
|
---|
[1728] | 23 | // TODO rename getDeviceInformation() and getAppInformation() to set ... use
|
---|
| 24 | // writeToFile for both
|
---|
| 25 |
|
---|
[1725] | 26 | private String name;
|
---|
[1728] | 27 | private File file;
|
---|
[1725] | 28 |
|
---|
[1726] | 29 | public AndroidmonitorLogFile(String appName, File dir) {
|
---|
| 30 | this.name = "android_" + appName + "_LogFile.xml";
|
---|
[1725] | 31 |
|
---|
| 32 | try {
|
---|
[1726] | 33 | // prove if file exists
|
---|
[1728] | 34 | this.file = new File(dir, this.name);
|
---|
[1726] | 35 | /*
|
---|
| 36 | * if file does not exists write device and app information to a new
|
---|
| 37 | * file. Otherwise use existing file and add activity information to
|
---|
| 38 | * file.
|
---|
| 39 | */
|
---|
[1728] | 40 | if (true) { // !this.file.exists()
|
---|
[1726] | 41 | /*
|
---|
| 42 | * create log file. Using method openFileOutput() does not work
|
---|
| 43 | * for this project due to the reason that this method would try
|
---|
| 44 | * to create the file in the directory of the non-existing
|
---|
| 45 | * directory de.ugoe.cs.androidmonitor. This directory does not
|
---|
| 46 | * exist due to the reason that this project is a library and
|
---|
| 47 | * the file has to be stored in the directory of the running
|
---|
| 48 | * application. Furthermore it would not be possible to write in
|
---|
| 49 | * another app directory as the own one.
|
---|
| 50 | */
|
---|
[1728] | 51 |
|
---|
| 52 | // TODO split document head information from
|
---|
| 53 | // getDeviceInformation.
|
---|
| 54 |
|
---|
| 55 | String string = "<?xml version='1.0' encoding='UTF-8' standalone='yes' ?><session>"
|
---|
| 56 | + getDeviceInformation() + getAppInformation();
|
---|
[1725] | 57 | try {
|
---|
[1728] | 58 | FileOutputStream outputStream = new FileOutputStream(
|
---|
| 59 | this.file);
|
---|
[1726] | 60 | outputStream.write(string.getBytes());
|
---|
| 61 | outputStream.close();
|
---|
| 62 | } catch (Exception e) {
|
---|
[1728] | 63 | Log.e("this.file", "outputstream: " + e.getMessage());
|
---|
[1725] | 64 | }
|
---|
| 65 |
|
---|
[1728] | 66 | } else {
|
---|
[1745] | 67 | // TODO add activity information
|
---|
[1725] | 68 | }
|
---|
| 69 | } catch (Exception e) {
|
---|
| 70 | e.printStackTrace();
|
---|
[1726] | 71 | Log.e("file", "file: " + e.getMessage());
|
---|
[1725] | 72 | }
|
---|
| 73 |
|
---|
| 74 | }
|
---|
| 75 |
|
---|
| 76 | /**
|
---|
[1756] | 77 | * <p>
|
---|
| 78 | * Get file name which is in use.
|
---|
| 79 | * </p>
|
---|
[1725] | 80 | *
|
---|
[1756] | 81 | * @return filename
|
---|
| 82 | *
|
---|
[1725] | 83 | */
|
---|
| 84 | public String getName() {
|
---|
| 85 | return this.name;
|
---|
| 86 | }
|
---|
| 87 |
|
---|
[1728] | 88 | // should be set
|
---|
[1725] | 89 | private String getAppInformation() {
|
---|
[1728] | 90 | // TODO create app information in the same manner as coded in
|
---|
| 91 | // getDeviceInformation
|
---|
[1725] | 92 | return "";
|
---|
| 93 | }
|
---|
[1726] | 94 |
|
---|
[1728] | 95 | /**
|
---|
[1756] | 96 | * <p>
|
---|
| 97 | * Query device information.
|
---|
| 98 | * </p>
|
---|
[1728] | 99 | *
|
---|
[1756] | 100 | * @return XML device information in XML format
|
---|
[1728] | 101 | */
|
---|
| 102 | // should be set
|
---|
[1726] | 103 | private String getDeviceInformation() {
|
---|
| 104 | String deviceInformation = "";
|
---|
[1728] | 105 | XmlSerializer serializer = Xml.newSerializer();
|
---|
[1726] | 106 | StringWriter writer = new StringWriter();
|
---|
[1725] | 107 | try {
|
---|
[1726] | 108 | serializer.setOutput(writer);
|
---|
| 109 | serializer.startTag("", "device");
|
---|
| 110 | serializer.startTag("", "param");
|
---|
| 111 | serializer.attribute("", "value", ""
|
---|
| 112 | + android.os.Build.VERSION.SDK_INT);
|
---|
| 113 | serializer.attribute("", "name", "sdk_version");
|
---|
| 114 | serializer.endTag("", "param");
|
---|
| 115 |
|
---|
| 116 | serializer.startTag("", "param");
|
---|
| 117 | serializer.attribute("", "value", android.os.Build.DEVICE);
|
---|
| 118 | serializer.attribute("", "name", "device");
|
---|
| 119 | serializer.endTag("", "param");
|
---|
| 120 |
|
---|
| 121 | serializer.startTag("", "param");
|
---|
| 122 | serializer.attribute("", "value", android.os.Build.MANUFACTURER);
|
---|
| 123 | serializer.attribute("", "name", "manufacturer");
|
---|
| 124 | serializer.endTag("", "param");
|
---|
| 125 |
|
---|
| 126 | serializer.startTag("", "param");
|
---|
| 127 | serializer.attribute("", "value", android.os.Build.MODEL);
|
---|
| 128 | serializer.attribute("", "name", "model");
|
---|
| 129 | serializer.endTag("", "param");
|
---|
| 130 |
|
---|
[1728] | 131 | // TODO get resolution ...
|
---|
[1726] | 132 |
|
---|
| 133 | serializer.endTag("", "device");
|
---|
| 134 | serializer.endDocument();
|
---|
[1728] | 135 |
|
---|
[1726] | 136 | deviceInformation = writer.toString();
|
---|
| 137 |
|
---|
[1728] | 138 | } catch (IOException e) {
|
---|
| 139 | Log.e("xml", e.getMessage());
|
---|
[1725] | 140 | }
|
---|
[1726] | 141 |
|
---|
[1725] | 142 | return deviceInformation;
|
---|
| 143 | }
|
---|
| 144 |
|
---|
[1756] | 145 | /**
|
---|
| 146 | * <p>
|
---|
| 147 | * Adds some information of an component of an activity (view) to the file.
|
---|
| 148 | * </p>
|
---|
| 149 | *
|
---|
| 150 | * @param view
|
---|
| 151 | * view to be logged
|
---|
| 152 | * @param parentHash
|
---|
| 153 | * hash of the parent view
|
---|
| 154 | * @param activityName
|
---|
| 155 | * name of the activity that is analyzed
|
---|
| 156 | */
|
---|
[1745] | 157 | public void addComponent(View view, int parentHash, String activityName) {
|
---|
[1728] | 158 | XmlSerializer serializer = Xml.newSerializer();
|
---|
| 159 | StringWriter writer = new StringWriter();
|
---|
| 160 | // create HEX string
|
---|
| 161 |
|
---|
| 162 | try {
|
---|
| 163 | serializer.setOutput(writer);
|
---|
| 164 | serializer.startTag("", "component");
|
---|
[1756] | 165 | // TODO find a way in that the hash code is unique over time and
|
---|
| 166 | // target
|
---|
| 167 | /*
|
---|
| 168 | * (non-Javadoc) view.getId() seems to be unique over time and
|
---|
| 169 | * targets but there is a problem. In some cases there is no ID
|
---|
| 170 | * (value: -1).
|
---|
| 171 | */
|
---|
[1728] | 172 | serializer.attribute("", "hash", "" + view.hashCode());
|
---|
| 173 |
|
---|
| 174 | serializer.startTag("", "param");
|
---|
| 175 | serializer.attribute("", "name", "id");
|
---|
| 176 | serializer.attribute("", "value", "" + view.getId());
|
---|
| 177 | serializer.endTag("", "param");
|
---|
| 178 |
|
---|
| 179 | serializer.startTag("", "param");
|
---|
| 180 | serializer.attribute("", "name", "path");
|
---|
| 181 | serializer.attribute("", "value", activityName + "/"
|
---|
[1745] | 182 | + getViewPath(view) + view.getClass().getSimpleName());
|
---|
[1728] | 183 | serializer.endTag("", "param");
|
---|
| 184 |
|
---|
| 185 | serializer.startTag("", "param");
|
---|
| 186 | serializer.attribute("", "name", "class");
|
---|
| 187 | serializer.attribute("", "value", view.getClass().getName());
|
---|
| 188 | serializer.endTag("", "param");
|
---|
| 189 |
|
---|
| 190 | serializer.startTag("", "param");
|
---|
| 191 | serializer.attribute("", "name", "parent");
|
---|
[1745] | 192 | // Problem in using view.getParent().hashCode():
|
---|
| 193 | // http://developer.android.com/reference/android/view/View.html#getParent()
|
---|
| 194 | // tells: "... parent is a ViewParent and not necessarily a View."
|
---|
| 195 | // ViewParent does not have a method hashCode(). Solution is done
|
---|
| 196 | // add parentHash as parameter to method addComponent() and
|
---|
| 197 | // Androidmonitor-> addLogListenerToView.
|
---|
| 198 | serializer.attribute("", "value", "" + parentHash);
|
---|
[1728] | 199 | serializer.endTag("", "param");
|
---|
| 200 |
|
---|
[1756] | 201 | // TODO add title e.g. android:text="Button"
|
---|
| 202 |
|
---|
| 203 | // TODO add ancestors @see:
|
---|
| 204 | // de.ugoe.cs.autoquest.jfcmonitor.JFCComponent#getClassHierarchy()
|
---|
| 205 |
|
---|
[1728] | 206 | serializer.endTag("", "component");
|
---|
| 207 | serializer.endDocument();
|
---|
| 208 |
|
---|
| 209 | writeToFile(writer.toString());
|
---|
| 210 |
|
---|
| 211 | } catch (IllegalArgumentException e) {
|
---|
| 212 | // TODO Auto-generated catch block
|
---|
| 213 | e.printStackTrace();
|
---|
| 214 | Log.e("file", "outputstream: " + e.getMessage());
|
---|
| 215 | } catch (IllegalStateException e) {
|
---|
| 216 | // TODO Auto-generated catch block
|
---|
| 217 | e.printStackTrace();
|
---|
| 218 | Log.e("file", "outputstream: " + e.getMessage());
|
---|
| 219 | } catch (IOException e) {
|
---|
| 220 | // TODO Auto-generated catch block
|
---|
| 221 | e.printStackTrace();
|
---|
| 222 | Log.e("file", "outputstream: " + e.getMessage());
|
---|
| 223 | }
|
---|
| 224 |
|
---|
[1725] | 225 | }
|
---|
[1726] | 226 |
|
---|
[1756] | 227 | /**
|
---|
| 228 | * <p>
|
---|
| 229 | * Add an event to the log file
|
---|
| 230 | * </p>
|
---|
| 231 | *
|
---|
| 232 | * @param view
|
---|
| 233 | * the calling view of the listener
|
---|
| 234 | * @param type
|
---|
| 235 | * the type of listener e.g. onClick ...
|
---|
| 236 | */
|
---|
| 237 | public void addEvent(View view, String type) {
|
---|
[1728] | 238 |
|
---|
| 239 | String x = "" + view.getX();
|
---|
| 240 | String y = "" + view.getY();
|
---|
| 241 |
|
---|
| 242 | XmlSerializer serializer = Xml.newSerializer();
|
---|
| 243 | StringWriter writer = new StringWriter();
|
---|
| 244 |
|
---|
| 245 | try {
|
---|
| 246 | serializer.setOutput(writer);
|
---|
| 247 |
|
---|
| 248 | serializer.startTag("", "event");
|
---|
[1756] | 249 | serializer.attribute("", "id", type);
|
---|
[1728] | 250 |
|
---|
| 251 | serializer.startTag("", "param");
|
---|
| 252 | serializer.attribute("", "value", x);
|
---|
| 253 | serializer.attribute("", "name", "X");
|
---|
| 254 | serializer.endTag("", "param");
|
---|
| 255 |
|
---|
| 256 | serializer.startTag("", "param");
|
---|
| 257 | serializer.attribute("", "value", y);
|
---|
| 258 | serializer.attribute("", "name", "Y");
|
---|
| 259 | serializer.endTag("", "param");
|
---|
| 260 |
|
---|
| 261 | serializer.startTag("", "param");
|
---|
| 262 | serializer.attribute("", "value", "" + view.hashCode());
|
---|
| 263 | serializer.attribute("", "name", "source");
|
---|
| 264 | serializer.endTag("", "param");
|
---|
| 265 |
|
---|
| 266 | serializer.startTag("", "param");
|
---|
| 267 | serializer.attribute("", "value", "" + System.currentTimeMillis());
|
---|
| 268 | serializer.attribute("", "name", "timestamp");
|
---|
| 269 | serializer.endTag("", "param");
|
---|
| 270 |
|
---|
| 271 | serializer.endTag("", "event");
|
---|
| 272 | serializer.endDocument();
|
---|
| 273 |
|
---|
| 274 | writeToFile(writer.toString());
|
---|
| 275 | } catch (IllegalArgumentException e) {
|
---|
| 276 | // TODO Auto-generated catch block
|
---|
| 277 | e.printStackTrace();
|
---|
| 278 | Log.e("file", "outputstream: " + e.getMessage());
|
---|
| 279 | } catch (IllegalStateException e) {
|
---|
| 280 | // TODO Auto-generated catch block
|
---|
| 281 | e.printStackTrace();
|
---|
| 282 | Log.e("file", "outputstream: " + e.getMessage());
|
---|
| 283 | } catch (IOException e) {
|
---|
| 284 | // TODO Auto-generated catch block
|
---|
| 285 | e.printStackTrace();
|
---|
| 286 | Log.e("file", "outputstream: " + e.getMessage());
|
---|
| 287 | }
|
---|
[1725] | 288 | }
|
---|
[1726] | 289 |
|
---|
[1756] | 290 | /**
|
---|
| 291 | * <p>
|
---|
| 292 | * Writes given information to the file. e.g. previous produced XML
|
---|
| 293 | * statements.
|
---|
| 294 | * </p>
|
---|
| 295 | *
|
---|
| 296 | * @param data
|
---|
| 297 | * content to add to the file
|
---|
| 298 | */
|
---|
[1728] | 299 | private void writeToFile(String data) {
|
---|
| 300 |
|
---|
| 301 | FileOutputStream outputStream;
|
---|
| 302 | try {
|
---|
| 303 | outputStream = new FileOutputStream(file, true);
|
---|
| 304 | outputStream.write(data.getBytes());
|
---|
| 305 | outputStream.close();
|
---|
| 306 | } catch (FileNotFoundException e) {
|
---|
| 307 | e.printStackTrace();
|
---|
| 308 | Log.e("file", "outputstream: " + e.getMessage());
|
---|
| 309 | } catch (IOException e) {
|
---|
| 310 | e.printStackTrace();
|
---|
| 311 | Log.e("file", "outputstream: " + e.getMessage());
|
---|
| 312 | }
|
---|
| 313 |
|
---|
| 314 | }
|
---|
| 315 |
|
---|
| 316 | /**
|
---|
[1756] | 317 | * <p>
|
---|
| 318 | * Generates the path of an view element.
|
---|
| 319 | * </p>
|
---|
[1728] | 320 | *
|
---|
| 321 | * @param view
|
---|
[1756] | 322 | * @return path path to the element
|
---|
[1728] | 323 | */
|
---|
| 324 | private String getViewPath(View view) {
|
---|
| 325 | return getViewPath(view, null);
|
---|
| 326 | }
|
---|
| 327 |
|
---|
| 328 | /**
|
---|
[1756] | 329 | * <p>
|
---|
| 330 | * Generates the path of an view element.
|
---|
| 331 | * </p>
|
---|
[1728] | 332 | *
|
---|
| 333 | * @param view
|
---|
| 334 | * @param path
|
---|
[1756] | 335 | * @return path path to the element
|
---|
[1728] | 336 | */
|
---|
| 337 | private String getViewPath(View view, String path) {
|
---|
| 338 | if (path == null) {
|
---|
| 339 | path = "";
|
---|
| 340 | } else {
|
---|
| 341 | path = view.getClass().getSimpleName() + "/" + path;
|
---|
| 342 | }
|
---|
| 343 | if (view.getParent() != null && (view.getParent() instanceof ViewGroup)) {
|
---|
| 344 | return getViewPath((View) view.getParent(), path);
|
---|
| 345 | } else {
|
---|
| 346 | return path;
|
---|
| 347 | }
|
---|
| 348 | }
|
---|
| 349 |
|
---|
[1725] | 350 | }
|
---|