source: trunk/autoquest-androidmonitor/src/main/java/de/ugoe/cs/autoquest/androidmonitor/AndroidMonitorLogFile.java @ 1882

Last change on this file since 1882 was 1882, checked in by funger, 9 years ago
  • Monitor the position of the element in the original GUI.
  • Property svn:mime-type set to text/plain
File size: 20.8 KB
Line 
1//   Copyright 2012 Georg-August-Universität Göttingen, Germany
2//
3//   Licensed under the Apache License, Version 2.0 (the "License");
4//   you may not use this file except in compliance with the License.
5//   You may obtain a copy of the License at
6//
7//       http://www.apache.org/licenses/LICENSE-2.0
8//
9//   Unless required by applicable law or agreed to in writing, software
10//   distributed under the License is distributed on an "AS IS" BASIS,
11//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//   See the License for the specific language governing permissions and
13//   limitations under the License.
14
15package de.ugoe.cs.autoquest.androidmonitor;
16
17import java.io.File;
18import java.io.FileNotFoundException;
19import java.io.FileOutputStream;
20import java.io.IOException;
21import java.io.StringWriter;
22import java.util.ArrayList;
23import java.util.List;
24
25import org.xmlpull.v1.XmlSerializer;
26
27import android.app.Activity;
28import android.content.Context;
29import android.content.pm.ApplicationInfo;
30import android.content.pm.PackageManager;
31import android.content.pm.PackageManager.NameNotFoundException;
32import android.util.Log;
33import android.util.Xml;
34import android.view.View;
35import android.view.ViewGroup;
36import android.widget.ImageView;
37import android.widget.TextView;
38
39/**
40 * <p>
41 * Writes informations about the device, the application, the components of the activity and the
42 * events in a log file. File is stored in the space of the application. Path is normally internal
43 * storage: data/data/<package name of the application using the AndroidMonitor>/files/ e.g.
44 * data/data/de.ugoe.cs.autoquest.androidmonitor.testApp/files/
45 * </p>
46 *
47 * @author Florian Unger
48 * @version 1.0
49 */
50public class AndroidMonitorLogFile {
51
52    /**
53     * <p>
54     * Name of the log file which is stored in the internal space of the device.
55     * </p>
56     */
57    private static String name;
58
59    /**
60     * <p>
61     * Name of the Application which is monitored.
62     * </p>
63     */
64    private static String appName;
65
66    /**
67     * <p>
68     * File representation to store monitored information.
69     * </p>
70     */
71    private static File file;
72
73    /**
74     * <p>
75     * List representing all components which was written to log file before.
76     * </p>
77     */
78    private static List<Integer> currentLoggedComponents;
79
80    /**
81     *
82     * <p>
83     * Constructor. Creates a new AndroidmonitorLogFile.
84     * </p>
85     *
86     * @param appName
87     *            Name of the calling application.
88     * @param dir
89     *            Folder to store the log file.
90     */
91    public AndroidMonitorLogFile(Activity activity) {
92        createFile(activity);
93    }
94
95    /**
96     *
97     * <p>
98     * Get file name which is in use.
99     * </p>
100     *
101     * @return filename
102     */
103    public static String getFileName() {
104        return AndroidMonitorLogFile.name;
105    }
106
107    /**
108     * Get application name as defined in Package Name and write it to appName.
109     *
110     * @param pContext
111     *            package context; could also be an activity
112     * @return app name
113     */
114    private String getAppLable(Context pContext) {
115        // source:
116        // http://stackoverflow.com/questions/11229219/android-get-application-name-not-package-name
117        // (last call 2014-09-04)
118        String appLabel;
119        PackageManager lPackageManager = pContext.getPackageManager();
120        ApplicationInfo lApplicationInfo = null;
121        try {
122            lApplicationInfo =
123                lPackageManager.getApplicationInfo(pContext.getApplicationInfo().packageName, 0);
124        }
125        catch (final NameNotFoundException e) {
126           
127        }
128        appLabel = (String) (lApplicationInfo != null ? lPackageManager
129            .getApplicationLabel(lApplicationInfo) : "Unknown");
130        return appLabel;
131    }
132
133    /**
134     *
135     * <p>
136     * Get package Name.
137     * </p>
138     *
139     * @param pContext
140     *            package context; could also be an activity
141     * @return package name
142     */
143    private String getAppPackageName(Context pContext) {
144        return pContext.getPackageName();
145    }
146
147    /**
148     *
149     * <p>
150     * Writes information about the application to the log file.
151     * </p>
152     *
153     * @param activity
154     *
155     */
156    private void setAppInformation(Activity activity) {
157
158        XmlSerializer serializer = Xml.newSerializer();
159        StringWriter writer = new StringWriter();
160        try {
161            serializer.setOutput(writer);
162
163            serializer.startTag("", "application");
164
165            serializer.startTag("", "param");
166            serializer.attribute("", "value", getAppPackageName(activity));
167            serializer.attribute("", "name", "package");
168            serializer.endTag("", "param");
169
170            serializer.startTag("", "param");
171            serializer.attribute("", "value", getAppLable(activity));
172            serializer.attribute("", "name", "name");
173            serializer.endTag("", "param");
174
175            serializer.endTag("", "application");
176            serializer.endDocument();
177
178            writeToFile(writer.toString());
179        }
180        catch (IllegalArgumentException e) {
181            e.printStackTrace();
182            Log.e("file", "outputstream: " + e.getMessage());
183        }
184        catch (IllegalStateException e) {
185            e.printStackTrace();
186            Log.e("file", "outputstream: " + e.getMessage());
187        }
188        catch (IOException e) {
189            e.printStackTrace();
190            Log.e("file", "outputstream: " + e.getMessage());
191        }
192    }
193
194    /**
195     * <p>
196     * Query device information and store it to log file.
197     * </p>
198     *
199     */
200    private void setDeviceInformation() {
201
202        XmlSerializer serializer = Xml.newSerializer();
203        StringWriter writer = new StringWriter();
204        try {
205            serializer.setOutput(writer);
206            serializer.startTag("", "device");
207            serializer.startTag("", "param");
208            serializer.attribute("", "value", "" + android.os.Build.VERSION.SDK_INT);
209            serializer.attribute("", "name", "sdk_version");
210            serializer.endTag("", "param");
211
212            serializer.startTag("", "param");
213            serializer.attribute("", "value", android.os.Build.DEVICE);
214            serializer.attribute("", "name", "device");
215            serializer.endTag("", "param");
216
217            serializer.startTag("", "param");
218            serializer.attribute("", "value", android.os.Build.MANUFACTURER);
219            serializer.attribute("", "name", "manufacturer");
220            serializer.endTag("", "param");
221
222            serializer.startTag("", "param");
223            serializer.attribute("", "value", android.os.Build.MODEL);
224            serializer.attribute("", "name", "model");
225            serializer.endTag("", "param");
226
227            // TODO get resolution ...
228
229            serializer.endTag("", "device");
230            serializer.endDocument();
231
232            writeToFile(writer.toString());
233
234        }
235        catch (IllegalArgumentException e) {
236            e.printStackTrace();
237            Log.e("file", "outputstream: " + e.getMessage());
238        }
239        catch (IllegalStateException e) {
240            e.printStackTrace();
241            Log.e("file", "outputstream: " + e.getMessage());
242        }
243        catch (IOException e) {
244            e.printStackTrace();
245            Log.e("file", "outputstream: " + e.getMessage());
246        }
247
248    }
249
250    /**
251     * <p>
252     * Adds some information of an component of an activity (view) to the file.
253     * </p>
254     *
255     * @param view
256     *            view to be logged
257     * @param parentHash
258     *            hash of the parent view
259     * @param activityName
260     *            name of the activity that is analyzed
261     */
262    public void addComponent(View view, int parentHash, String activityName, int position) {
263        XmlSerializer serializer = Xml.newSerializer();
264        StringWriter writer = new StringWriter();
265
266        try {
267            serializer.setOutput(writer);
268            serializer.startTag("", "component");
269            /*
270             * (non-Javadoc)
271             * TODO find a way in that the hash code is unique over time and target
272             *
273             * view.getId() seems to be unique over time and targets but there is a problem. In some
274             * cases there is no ID (value: -1).
275             *
276             * view.getId() returns different values in case of some identical components.
277             * E.g. in the application timerdroid the id of the list elements
278             * changes when calling home button.
279             */
280            serializer.attribute("", "hash", "" + view.hashCode());
281            currentLoggedComponents.add(view.hashCode());
282
283            /*
284             * (non-Javadoc)
285             * http://developer.android.com/reference/android/view/View.html#getId()
286             * Returns this view's identifier.
287             */
288            serializer.startTag("", "param");
289            serializer.attribute("", "name", "id");
290            serializer.attribute("", "value", "" + view.getId());
291            serializer.endTag("", "param");
292           
293            serializer.startTag("", "param");
294            serializer.attribute("", "name", "position");
295            serializer.attribute("", "value", "" + position);
296            serializer.endTag("", "param");
297
298            if (view instanceof TextView) {
299                serializer.startTag("", "param");
300                serializer.attribute("", "name", "title");
301                TextView textView = (TextView) view;
302                serializer.attribute("", "value", "" + textView.getText());
303                serializer.endTag("", "param");
304            }
305            //TODO in case of an image add file name
306            if (view instanceof ImageView) {
307                serializer.startTag("", "param");
308                serializer.attribute("", "name", "title");
309                serializer.attribute("", "value", "image:" );
310                serializer.endTag("", "param");
311            }
312
313            serializer.startTag("", "param");
314            serializer.attribute("", "name", "path");
315            serializer.attribute("", "value", activityName + "/" + getViewPath(view) +
316                view.getClass().getSimpleName());
317            serializer.endTag("", "param");
318
319            serializer.startTag("", "param");
320            serializer.attribute("", "name", "class");
321            serializer.attribute("", "value", view.getClass().getName());
322            serializer.endTag("", "param");
323
324            serializer.startTag("", "param");
325            serializer.attribute("", "name", "parent");
326            /*
327             * (non-Javadoc)
328             * Problem in using view.getParent().hashCode():
329             * http://developer.android.com/reference/android/view/View.html#getParent() tells:
330             * "... parent is a ViewParent and not necessarily a View." ViewParent does not have a
331             * method hashCode(). Solution is done add parentHash as parameter to method
332             * addComponent() and Androidmonitor-> addLogListenerToView.
333             */
334            serializer.attribute("", "value", "" + parentHash);
335            serializer.endTag("", "param");
336
337            serializer.startTag("", "ancestors");
338
339            Class<? extends Object> classobject = view.getClass();
340
341            while ((classobject != null)) {
342                serializer.startTag("", "ancestor");
343                serializer.attribute("", "name", classobject.getName());
344                serializer.endTag("", "ancestor");
345                classobject = classobject.getSuperclass();
346            }
347            serializer.endTag("", "ancestors");
348
349            serializer.endTag("", "component");
350            serializer.endDocument();
351
352            writeToFile(writer.toString());
353
354        }
355        catch (IllegalArgumentException e) {
356            e.printStackTrace();
357            Log.e("file", "outputstream: " + e.getMessage());
358        }
359        catch (IllegalStateException e) {
360            e.printStackTrace();
361            Log.e("file", "outputstream: " + e.getMessage());
362        }
363        catch (IOException e) {
364            e.printStackTrace();
365            Log.e("file", "outputstream: " + e.getMessage());
366        }
367
368    }
369
370    /**
371     * <p>
372     * Add an event to the log file
373     * </p>
374     *
375     * @param hash
376     *            hash value of the calling view of the listener
377     * @param type
378     *            the type of listener e.g. textView ...
379     * @param message
380     *            message typed in
381     */
382    public void addEvent(int hash, String type, String message) {
383        XmlSerializer serializer = Xml.newSerializer();
384        StringWriter writer = new StringWriter();
385
386        try {
387            serializer.setOutput(writer);
388
389            serializer.startTag("", "event");
390            serializer.attribute("", "id", type);
391
392            serializer.startTag("", "param");
393            serializer.attribute("", "value", "" + hash);
394            serializer.attribute("", "name", "source");
395            serializer.endTag("", "param");
396
397            serializer.startTag("", "param");
398            serializer.attribute("", "value", message);
399            serializer.attribute("", "name", "message");
400            serializer.endTag("", "param");
401
402            serializer.startTag("", "param");
403            serializer.attribute("", "value", "" + System.currentTimeMillis());
404            serializer.attribute("", "name", "timestamp");
405            serializer.endTag("", "param");
406
407            serializer.endTag("", "event");
408            serializer.endDocument();
409
410            writeToFile(writer.toString());
411        }
412        catch (IllegalArgumentException e) {
413            e.printStackTrace();
414            Log.e("file", "outputstream: " + e.getMessage());
415        }
416        catch (IllegalStateException e) {
417            e.printStackTrace();
418            Log.e("file", "outputstream: " + e.getMessage());
419        }
420        catch (IOException e) {
421            e.printStackTrace();
422            Log.e("file", "outputstream: " + e.getMessage());
423        }
424    }
425
426    /**
427     * <p>
428     * Add an event to the log file
429     * </p>
430     *
431     * @param view
432     *            the calling view of the listener
433     * @param type
434     *            the type of listener e.g. onClick ...
435     */
436    public void addEvent(View view, String type) {
437
438        String x = "" + view.getX();
439        String y = "" + view.getY();
440
441        XmlSerializer serializer = Xml.newSerializer();
442        StringWriter writer = new StringWriter();
443
444        try {
445            serializer.setOutput(writer);
446
447            serializer.startTag("", "event");
448            serializer.attribute("", "id", type);
449
450            serializer.startTag("", "param");
451            serializer.attribute("", "value", x);
452            serializer.attribute("", "name", "X");
453            serializer.endTag("", "param");
454
455            serializer.startTag("", "param");
456            serializer.attribute("", "value", y);
457            serializer.attribute("", "name", "Y");
458            serializer.endTag("", "param");
459
460            serializer.startTag("", "param");
461            serializer.attribute("", "value", "" + view.hashCode());
462            serializer.attribute("", "name", "source");
463            serializer.endTag("", "param");
464
465            serializer.startTag("", "param");
466            serializer.attribute("", "value", "" + System.currentTimeMillis());
467            serializer.attribute("", "name", "timestamp");
468            serializer.endTag("", "param");
469
470            serializer.endTag("", "event");
471            serializer.endDocument();
472
473            writeToFile(writer.toString());
474        }
475        catch (IllegalArgumentException e) {
476            e.printStackTrace();
477            Log.e("file", "outputstream: " + e.getMessage());
478        }
479        catch (IllegalStateException e) {
480            e.printStackTrace();
481            Log.e("file", "outputstream: " + e.getMessage());
482        }
483        catch (IOException e) {
484            e.printStackTrace();
485            Log.e("file", "outputstream: " + e.getMessage());
486        }
487    }
488
489    /**
490     *
491     * <p>
492     * Creates a new file to store information.
493     * </p>
494     *
495     * @param activity
496     *            Calling application.
497     */
498    private void createFile(Activity activity) {
499       
500        AndroidMonitorLogFile.appName = getAppLable(activity);
501        AndroidMonitorLogFile.name =
502            "androidLogFile_" + AndroidMonitorLogFile.appName + System.currentTimeMillis() + ".log";
503        try {
504            AndroidMonitorLogFile.file =
505                new File(activity.getFilesDir(), AndroidMonitorLogFile.name);
506            if (AndroidMonitorLogFile.file.exists() && !AndroidMonitorLogFile.file.isDirectory()) {
507                createFile(activity, 0);               
508            }
509            else {
510                AndroidMonitorLogFile.currentLoggedComponents = new ArrayList<Integer>();
511                writeHeaderToFile(activity);
512               
513            }
514        }
515        catch (Exception e) {
516            e.printStackTrace();
517            Log.e("AndroidMonitorLogFile.file", "file: " + e.getMessage());
518        }
519    }
520
521    /**
522     *
523     * <p>
524     * Creates a new file to store information. Counts up if file exists.
525     * </p>
526     *
527     * @param activity
528     *            Calling application.
529     * @param count
530     *            File number.
531     */
532    private void createFile(Activity activity, int count) {
533        AndroidMonitorLogFile.name =
534            "androidLogFile_" + count + "_" + AndroidMonitorLogFile.appName +
535                System.currentTimeMillis() + ".log";
536       
537        try {
538            AndroidMonitorLogFile.file =
539                new File(activity.getFilesDir(), AndroidMonitorLogFile.name);
540            if (AndroidMonitorLogFile.file.exists() && !AndroidMonitorLogFile.file.isDirectory()) {
541                count++;
542                createFile(activity, count);
543            }
544            else {
545                writeHeaderToFile(activity);
546            }
547        }
548        catch (Exception e) {
549            e.printStackTrace();
550            Log.e("AndroidMonitorLogFile.file", "file: " + e.getMessage());
551        }
552    }
553
554    /**
555     *
556     * <p>
557     * Writes XML head, device and application information to file.
558     * </p>
559     *
560     * @param activity
561     *            Calling application.
562     */
563    private void writeHeaderToFile(Activity activity) {
564        writeToFile("<?xml version='1.0' encoding='UTF-8' standalone='yes' ?><sessions>");
565        setDeviceInformation();
566        setAppInformation(activity);
567    }
568
569    /**
570     * <p>
571     * Writes given information to the file. e.g. previous produced XML statements.
572     * </p>
573     *
574     * @param data
575     *            content to add to the file
576     */
577    private void writeToFile(String data) {
578
579        FileOutputStream outputStream;
580        try {
581            outputStream = new FileOutputStream(AndroidMonitorLogFile.file, true);
582            outputStream.write(data.getBytes());
583            outputStream.close();
584        }
585        catch (FileNotFoundException e) {
586            e.printStackTrace();
587            Log.e("file", "outputstream: " + e.getMessage());
588        }
589        catch (IOException e) {
590            e.printStackTrace();
591            Log.e("file", "outputstream: " + e.getMessage());
592        }
593
594    }
595
596    /**
597     * <p>
598     * Generates the path of an view element.
599     * </p>
600     *
601     * @param view
602     * @return path path to the element
603     */
604    private String getViewPath(View view) {
605        return getViewPath(view, null);
606    }
607
608    /**
609     * <p>
610     * Generates the path of an view element.
611     * </p>
612     *
613     * @param view
614     * @param path
615     * @return path path to the element
616     */
617    private String getViewPath(View view, String path) {
618        if (path == null) {
619            path = "";
620        }
621        else {
622            path = view.getClass().getSimpleName() + "/" + path;
623        }
624        if (view.getParent() != null && (view.getParent() instanceof ViewGroup)) {
625            return getViewPath((View) view.getParent(), path);
626        }
627        else {
628            return path;
629        }
630    }
631
632    /**
633     *
634     * <p>
635     * Check whether a component is still written to log file.
636     * </p>
637     *
638     * @param hashCode
639     *            hash code of the view
640     * @return
641     */
642    public static Boolean isComponentLogged(Integer hashCode) {
643        return AndroidMonitorLogFile.currentLoggedComponents.contains(hashCode);
644    }
645
646}
Note: See TracBrowser for help on using the repository browser.