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

Last change on this file since 1842 was 1842, checked in by funger, 10 years ago
  • Property svn:mime-type set to text/plain
File size: 20.2 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
93        AndroidMonitorLogFile.currentLoggedComponents = new ArrayList<Integer>();
94
95        AndroidMonitorLogFile.appName = getAppLable(activity);
96
97        createFile(activity);
98    }
99
100    /**
101     *
102     * <p>
103     * Get file name which is in use.
104     * </p>
105     *
106     * @return filename
107     */
108    public static String getFileName() {
109        return AndroidMonitorLogFile.name;
110    }
111
112    /**
113     * Get application name as defined in Package Name
114     *
115     * @param pContext
116     *            package context; could also be an activity
117     * @return app name
118     */
119    private String getAppLable(Context pContext) {
120        // source:
121        // http://stackoverflow.com/questions/11229219/android-get-application-name-not-package-name
122        // (last call 2014-09-04)
123        PackageManager lPackageManager = pContext.getPackageManager();
124        ApplicationInfo lApplicationInfo = null;
125        try {
126            lApplicationInfo =
127                lPackageManager.getApplicationInfo(pContext.getApplicationInfo().packageName, 0);
128        }
129        catch (final NameNotFoundException e) {}
130        return (String) (lApplicationInfo != null ? lPackageManager
131            .getApplicationLabel(lApplicationInfo) : "Unknown");
132    }
133
134    /**
135     *
136     * <p>
137     * Get package Name.
138     * </p>
139     *
140     * @param pContext
141     *            package context; could also be an activity
142     * @return package name
143     */
144    private String getAppPackageName(Context pContext) {
145        return pContext.getPackageName();
146    }
147
148    /**
149     *
150     * <p>
151     * Writes information about the application to the log file.
152     * </p>
153     *
154     * @param activity
155     *
156     */
157    private void setAppInformation(Activity activity) {
158
159        XmlSerializer serializer = Xml.newSerializer();
160        StringWriter writer = new StringWriter();
161        try {
162            serializer.setOutput(writer);
163
164            serializer.startTag("", "application");
165
166            serializer.startTag("", "param");
167            serializer.attribute("", "value", getAppPackageName(activity));
168            serializer.attribute("", "name", "package");
169            serializer.endTag("", "param");
170
171            serializer.startTag("", "param");
172            serializer.attribute("", "value", getAppLable(activity));
173            serializer.attribute("", "name", "name");
174            serializer.endTag("", "param");
175
176            serializer.endTag("", "application");
177            serializer.endDocument();
178
179            writeToFile(writer.toString());
180        }
181        catch (IllegalArgumentException e) {
182            e.printStackTrace();
183            Log.e("file", "outputstream: " + e.getMessage());
184        }
185        catch (IllegalStateException e) {
186            e.printStackTrace();
187            Log.e("file", "outputstream: " + e.getMessage());
188        }
189        catch (IOException e) {
190            e.printStackTrace();
191            Log.e("file", "outputstream: " + e.getMessage());
192        }
193    }
194
195    /**
196     * <p>
197     * Query device information and store it to log file.
198     * </p>
199     *
200     */
201    private void setDeviceInformation() {
202
203        XmlSerializer serializer = Xml.newSerializer();
204        StringWriter writer = new StringWriter();
205        try {
206            serializer.setOutput(writer);
207            serializer.startTag("", "device");
208            serializer.startTag("", "param");
209            serializer.attribute("", "value", "" + android.os.Build.VERSION.SDK_INT);
210            serializer.attribute("", "name", "sdk_version");
211            serializer.endTag("", "param");
212
213            serializer.startTag("", "param");
214            serializer.attribute("", "value", android.os.Build.DEVICE);
215            serializer.attribute("", "name", "device");
216            serializer.endTag("", "param");
217
218            serializer.startTag("", "param");
219            serializer.attribute("", "value", android.os.Build.MANUFACTURER);
220            serializer.attribute("", "name", "manufacturer");
221            serializer.endTag("", "param");
222
223            serializer.startTag("", "param");
224            serializer.attribute("", "value", android.os.Build.MODEL);
225            serializer.attribute("", "name", "model");
226            serializer.endTag("", "param");
227
228            // TODO get resolution ...
229
230            serializer.endTag("", "device");
231            serializer.endDocument();
232
233            writeToFile(writer.toString());
234
235        }
236        catch (IllegalArgumentException e) {
237            e.printStackTrace();
238            Log.e("file", "outputstream: " + e.getMessage());
239        }
240        catch (IllegalStateException e) {
241            e.printStackTrace();
242            Log.e("file", "outputstream: " + e.getMessage());
243        }
244        catch (IOException e) {
245            e.printStackTrace();
246            Log.e("file", "outputstream: " + e.getMessage());
247        }
248
249    }
250
251    /**
252     * <p>
253     * Adds some information of an component of an activity (view) to the file.
254     * </p>
255     *
256     * @param view
257     *            view to be logged
258     * @param parentHash
259     *            hash of the parent view
260     * @param activityName
261     *            name of the activity that is analyzed
262     */
263    public void addComponent(View view, int parentHash, String activityName) {
264        XmlSerializer serializer = Xml.newSerializer();
265        StringWriter writer = new StringWriter();
266
267        try {
268            serializer.setOutput(writer);
269            serializer.startTag("", "component");
270            /*
271             * (non-Javadoc) 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() is not unique in every case. E.g. in the application timerdroid the id
277             * of the list elements changes when calling home button.
278             */
279            serializer.attribute("", "hash", "" + view.hashCode());
280            currentLoggedComponents.add(view.hashCode());
281
282            serializer.startTag("", "param");
283            serializer.attribute("", "name", "id");
284            serializer.attribute("", "value", "" + view.getId());
285            serializer.endTag("", "param");
286
287            if (view instanceof TextView) {
288                serializer.startTag("", "param");
289                serializer.attribute("", "name", "title");
290                TextView textView = (TextView) view;
291                serializer.attribute("", "value", "" + textView.getText());
292                serializer.endTag("", "param");
293            }
294            //TODO in case of an image add file name
295            if (view instanceof ImageView) {
296                serializer.startTag("", "param");
297                serializer.attribute("", "name", "title");
298               
299               
300                serializer.attribute("", "value", "image:" );
301                serializer.endTag("", "param");
302            }
303
304            serializer.startTag("", "param");
305            serializer.attribute("", "name", "path");
306            serializer.attribute("", "value", activityName + "/" + getViewPath(view) +
307                view.getClass().getSimpleName());
308            serializer.endTag("", "param");
309
310            serializer.startTag("", "param");
311            serializer.attribute("", "name", "class");
312            serializer.attribute("", "value", view.getClass().getName());
313            serializer.endTag("", "param");
314
315            serializer.startTag("", "param");
316            serializer.attribute("", "name", "parent");
317            /*
318             * (non-Javadoc) Problem in using view.getParent().hashCode():
319             * http://developer.android.com/reference/android/view/View.html#getParent() tells:
320             * "... parent is a ViewParent and not necessarily a View." ViewParent does not have a
321             * method hashCode(). Solution is done add parentHash as parameter to method
322             * addComponent() and Androidmonitor-> addLogListenerToView.
323             */
324            serializer.attribute("", "value", "" + parentHash);
325            serializer.endTag("", "param");
326
327            serializer.startTag("", "ancestors");
328
329            Class<? extends Object> classobject = view.getClass();
330
331            while ((classobject != null)) {
332                serializer.startTag("", "ancestor");
333                serializer.attribute("", "name", classobject.getName());
334                serializer.endTag("", "ancestor");
335                classobject = classobject.getSuperclass();
336            }
337            serializer.endTag("", "ancestors");
338
339            serializer.endTag("", "component");
340            serializer.endDocument();
341
342            writeToFile(writer.toString());
343
344        }
345        catch (IllegalArgumentException e) {
346            e.printStackTrace();
347            Log.e("file", "outputstream: " + e.getMessage());
348        }
349        catch (IllegalStateException e) {
350            e.printStackTrace();
351            Log.e("file", "outputstream: " + e.getMessage());
352        }
353        catch (IOException e) {
354            e.printStackTrace();
355            Log.e("file", "outputstream: " + e.getMessage());
356        }
357
358    }
359
360    /**
361     * <p>
362     * Add an event to the log file
363     * </p>
364     *
365     * @param hash
366     *            hash value of the calling view of the listener
367     * @param type
368     *            the type of listener e.g. textView ...
369     * @param message
370     *            message typed in
371     */
372    public void addEvent(int hash, String type, String message) {
373        XmlSerializer serializer = Xml.newSerializer();
374        StringWriter writer = new StringWriter();
375
376        try {
377            serializer.setOutput(writer);
378
379            serializer.startTag("", "event");
380            serializer.attribute("", "id", type);
381
382            serializer.startTag("", "param");
383            serializer.attribute("", "value", "" + hash);
384            serializer.attribute("", "name", "source");
385            serializer.endTag("", "param");
386
387            serializer.startTag("", "param");
388            serializer.attribute("", "value", message);
389            serializer.attribute("", "name", "message");
390            serializer.endTag("", "param");
391
392            serializer.startTag("", "param");
393            serializer.attribute("", "value", "" + System.currentTimeMillis());
394            serializer.attribute("", "name", "timestamp");
395            serializer.endTag("", "param");
396
397            serializer.endTag("", "event");
398            serializer.endDocument();
399
400            writeToFile(writer.toString());
401        }
402        catch (IllegalArgumentException e) {
403            e.printStackTrace();
404            Log.e("file", "outputstream: " + e.getMessage());
405        }
406        catch (IllegalStateException e) {
407            e.printStackTrace();
408            Log.e("file", "outputstream: " + e.getMessage());
409        }
410        catch (IOException e) {
411            e.printStackTrace();
412            Log.e("file", "outputstream: " + e.getMessage());
413        }
414    }
415
416    /**
417     * <p>
418     * Add an event to the log file
419     * </p>
420     *
421     * @param view
422     *            the calling view of the listener
423     * @param type
424     *            the type of listener e.g. onClick ...
425     */
426    public void addEvent(View view, String type) {
427
428        String x = "" + view.getX();
429        String y = "" + view.getY();
430
431        XmlSerializer serializer = Xml.newSerializer();
432        StringWriter writer = new StringWriter();
433
434        try {
435            serializer.setOutput(writer);
436
437            serializer.startTag("", "event");
438            serializer.attribute("", "id", type);
439
440            serializer.startTag("", "param");
441            serializer.attribute("", "value", x);
442            serializer.attribute("", "name", "X");
443            serializer.endTag("", "param");
444
445            serializer.startTag("", "param");
446            serializer.attribute("", "value", y);
447            serializer.attribute("", "name", "Y");
448            serializer.endTag("", "param");
449
450            serializer.startTag("", "param");
451            serializer.attribute("", "value", "" + view.hashCode());
452            serializer.attribute("", "name", "source");
453            serializer.endTag("", "param");
454
455            serializer.startTag("", "param");
456            serializer.attribute("", "value", "" + System.currentTimeMillis());
457            serializer.attribute("", "name", "timestamp");
458            serializer.endTag("", "param");
459
460            serializer.endTag("", "event");
461            serializer.endDocument();
462
463            writeToFile(writer.toString());
464        }
465        catch (IllegalArgumentException e) {
466            e.printStackTrace();
467            Log.e("file", "outputstream: " + e.getMessage());
468        }
469        catch (IllegalStateException e) {
470            e.printStackTrace();
471            Log.e("file", "outputstream: " + e.getMessage());
472        }
473        catch (IOException e) {
474            e.printStackTrace();
475            Log.e("file", "outputstream: " + e.getMessage());
476        }
477    }
478
479    /**
480     *
481     * <p>
482     * Creates a new file to store information.
483     * </p>
484     *
485     * @param activity
486     *            Calling application.
487     */
488    private void createFile(Activity activity) {
489
490        AndroidMonitorLogFile.name =
491            "androidLogFile_" + AndroidMonitorLogFile.appName + System.currentTimeMillis() + ".log";
492        try {
493            AndroidMonitorLogFile.file =
494                new File(activity.getFilesDir(), AndroidMonitorLogFile.name);
495            if (AndroidMonitorLogFile.file.exists() && !AndroidMonitorLogFile.file.isDirectory()) {
496                createFile(activity, 0);
497            }
498            else {
499                writeHeaderToFile(activity);
500            }
501        }
502        catch (Exception e) {
503            e.printStackTrace();
504            Log.e("AndroidMonitorLogFile.file", "file: " + e.getMessage());
505        }
506    }
507
508    /**
509     *
510     * <p>
511     * Creates a new file to store information. Counts up if file exists.
512     * </p>
513     *
514     * @param activity
515     *            Calling application.
516     * @param count
517     *            File number.
518     */
519    private void createFile(Activity activity, int count) {
520        AndroidMonitorLogFile.name =
521            "androidLogFile_" + count + "_" + AndroidMonitorLogFile.appName +
522                System.currentTimeMillis() + ".log";
523        try {
524            AndroidMonitorLogFile.file =
525                new File(activity.getFilesDir(), AndroidMonitorLogFile.name);
526            if (AndroidMonitorLogFile.file.exists() && !AndroidMonitorLogFile.file.isDirectory()) {
527                count++;
528                createFile(activity, count);
529            }
530            else {
531                writeHeaderToFile(activity);
532            }
533        }
534        catch (Exception e) {
535            e.printStackTrace();
536            Log.e("AndroidMonitorLogFile.file", "file: " + e.getMessage());
537        }
538    }
539
540    /**
541     *
542     * <p>
543     * Writes XML head, device and application information to file.
544     * </p>
545     *
546     * @param activity
547     *            Calling application.
548     */
549    private void writeHeaderToFile(Activity activity) {
550        writeToFile("<?xml version='1.0' encoding='UTF-8' standalone='yes' ?><sessions>");
551        setDeviceInformation();
552        setAppInformation(activity);
553    }
554
555    /**
556     * <p>
557     * Writes given information to the file. e.g. previous produced XML statements.
558     * </p>
559     *
560     * @param data
561     *            content to add to the file
562     */
563    private void writeToFile(String data) {
564
565        FileOutputStream outputStream;
566        try {
567            outputStream = new FileOutputStream(AndroidMonitorLogFile.file, true);
568            outputStream.write(data.getBytes());
569            outputStream.close();
570        }
571        catch (FileNotFoundException e) {
572            e.printStackTrace();
573            Log.e("file", "outputstream: " + e.getMessage());
574        }
575        catch (IOException e) {
576            e.printStackTrace();
577            Log.e("file", "outputstream: " + e.getMessage());
578        }
579
580    }
581
582    /**
583     * <p>
584     * Generates the path of an view element.
585     * </p>
586     *
587     * @param view
588     * @return path path to the element
589     */
590    private String getViewPath(View view) {
591        return getViewPath(view, null);
592    }
593
594    /**
595     * <p>
596     * Generates the path of an view element.
597     * </p>
598     *
599     * @param view
600     * @param path
601     * @return path path to the element
602     */
603    private String getViewPath(View view, String path) {
604        if (path == null) {
605            path = "";
606        }
607        else {
608            path = view.getClass().getSimpleName() + "/" + path;
609        }
610        if (view.getParent() != null && (view.getParent() instanceof ViewGroup)) {
611            return getViewPath((View) view.getParent(), path);
612        }
613        else {
614            return path;
615        }
616    }
617
618    /**
619     *
620     * <p>
621     * Check whether a component is still written to log file.
622     * </p>
623     *
624     * @param hashCode
625     *            hash code of the view
626     * @return
627     */
628    public static Boolean isComponentLogged(Integer hashCode) {
629        return AndroidMonitorLogFile.currentLoggedComponents.contains(hashCode);
630    }
631
632}
Note: See TracBrowser for help on using the repository browser.