source: trunk/autoquest-plugin-android/src/main/java/de/ugoe/cs/autoquest/plugin/android/guimodel/ANDROIDGUIElementSpec.java @ 1880

Last change on this file since 1880 was 1880, checked in by funger, 9 years ago
  • Add the position of the element in the original GUI.
  • getSimilarity extended (path + title, path + position now compared)
  • Property svn:mime-type set to text/plain
File size: 10.4 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.plugin.android.guimodel;
16
17import java.util.List;
18
19import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElementSpec;
20
21/**
22 * <p>
23 * Implements the specification of {@link IGUIElement} for {@link ANDROIDGUIElement}s.
24 * </p>
25 *
26 * @version 1.0
27 * @author Florian Unger
28 */
29public class ANDROIDGUIElementSpec implements IGUIElementSpec {
30
31    /**
32     * <p>
33     * Default serial version UID
34     * </p>
35     */
36    private static final long serialVersionUID = 1L;
37
38    /*
39     * (non-Javadoc)
40     *
41     * @see de.ugoe.cs.autoquest.androidmonitor.AndroidmonitorLogFile#logComponent()
42     */
43    /**
44     * <p>
45     * Hash code of the GUI element. Used as unique identifier during parsing a log file. Note that
46     * it is possible that the hash code of an element changes over several log files even if they
47     * come from the same target.
48     * </p>
49     */
50    private int elementHash;
51
52    /**
53     * <p>
54     * Path to an element in an activity. e.g. a path of a button could look like
55     * MainActivity/DecorView/ActionBarOverlayLayout/FrameLayout/RelativeLayout/Button
56     * </p>
57     */
58    private String path;
59
60    /*
61     * (non-Javadoc)
62     *
63     * @see http://developer.android.com/reference/android/view/View.html#getId()
64     */
65    /**
66     * <p>
67     * Id of the object as it is returned by view.getId().
68     * </p>
69     */
70    private int index;
71
72    /**
73     * <p>
74     * Current name of the GUI element
75     * </p>
76     */
77    private String name;
78
79    /**
80     * <p>
81     * The type of GUI element, i.e., the class of the android GUI element.
82     * </p>
83     */
84    private String type;
85
86    /**
87     * <p>
88     * The position of the element in the original GUI.
89     * </p>
90     */
91    private int elementPosition;
92
93    /**
94     * <p>
95     * Type hierarchy of the class itself.
96     * </p>
97     */
98    private List<String> typeHierarchy = null;
99
100    /*
101     * (non-Javadoc)
102     *
103     * @see
104     * de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElementSpec#getSecificationSimilarity(IGUIElementSpec
105     * )
106     */
107    @Override
108    public boolean getSimilarity(IGUIElementSpec other) {
109        if (this == other) {
110            return true;
111        }
112
113        if (!(other instanceof ANDROIDGUIElementSpec)) {
114            return false;
115        }
116
117        ANDROIDGUIElementSpec otherSpec = (ANDROIDGUIElementSpec) other;
118
119        if (type == null ? otherSpec.type != null : !type.equals(otherSpec.type)) {
120            return false;
121        }
122
123        /*
124         * Up to now, we compared, if the basics match. Due to testing with different virtual
125         * devices it seems to be the case that the id of a view (named index here) keeps the same
126         * even on different devices even if the hashCode changes. Some of the GUI elements does not
127         * have an id (id is -1).
128         */
129
130        if (otherSpec.getIndex() > 1 && getIndex() == otherSpec.getIndex()) {
131            return true;
132        }
133
134        /*
135         * Path and label of the elements fits together. In this case it is most likely that this
136         * elements fits together. This only makes since in the case a label exists.
137         */
138        if (otherSpec.getName() != "NOT_SET" && getName() != "NOT_SET" &&
139            !otherSpec.getName().contains("image:") && getName().contains("image:") &&
140            otherSpec.getName() == getName() && otherSpec.getPath() == getPath())
141        {
142            return true;
143        }
144
145        /*
146         * Path and position fits together. In this case it is most likely that this elements fits
147         * together.
148         */
149        if (otherSpec.getPath() == getPath() &&
150            otherSpec.getElementPosition() == getElementPosition())
151        {
152            return true;
153        }
154
155        /*
156         * Two elements could also be similar if the path of the elements is equal and the name is
157         * set, equal and not equal to "image:" even if index <= 1. This comparison is not
158         * implemented up to know due to the reason that all recorded elements up to 2015/01 either
159         * have an index > 1 or no name to be compared.
160         *
161         * In all other cases up to know it is not clear if two elements are similar.
162         *
163         * Not working:
164         *
165         * - Position of the elements: Due to the reason that there are a lot of different displays
166         * on the android market and the in the most cases the layout depends on the display size
167         * (different resolutions) similar elements have different positions.
168         */
169
170        return false;
171    }
172
173    /*
174     * (non-Javadoc)
175     *
176     * @see de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElementSpec#getType()
177     */
178    @Override
179    public String getType() {
180        return type;
181    }
182
183    /*
184     * (non-Javadoc)
185     *
186     * @see de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElementSpec#getTypeHierarchy ()
187     */
188    @Override
189    public String[] getTypeHierarchy() {
190        if (typeHierarchy == null) {
191            return new String[]
192                { (getType()) };
193        }
194        else
195            return typeHierarchy.toArray(new String[typeHierarchy.size()]);
196    }
197
198    /**
199     * <p>
200     * Returns the object hash of the specified GUI element.
201     * </p>
202     *
203     * @return the elementHash
204     */
205    public int getElementHash() {
206        return elementHash;
207    }
208
209    /**
210     * <p>
211     * Returns the path associated with the specified GUI element.
212     * </p>
213     *
214     * @return the path to an element
215     */
216    public String getPath() {
217        return path;
218    }
219
220    /**
221     * <p>
222     * Returns the GUI element identifier.
223     * </p>
224     *
225     * @return identifier of the GUI element
226     */
227    public int getIndex() {
228        return index;
229    }
230
231    /**
232     * <p>
233     * Returns the name of the specified GUI element. Displayed text in the application or image
234     * name.
235     * </p>
236     *
237     * @return text or image of the GUI element.
238     */
239    public String getName() {
240        if (name == null || name.trim().length() == 0) {
241            return "NOT_SET";
242        }
243        return name;
244    }
245
246    /**
247     *
248     * <p>
249     * Return the position of the element in the original GUI.
250     * </p>
251     *
252     * @return position of the element in the original GUI.
253     */
254    public int getElementPosition() {
255        return elementPosition;
256    }
257
258    /**
259     *
260     * <p>
261     * Set the position of the element in the original GUI.
262     * </p>
263     *
264     * @param elementPosition
265     */
266    public void setElementPosition(int elementPosition) {
267        this.elementPosition = elementPosition;
268    }
269
270    /**
271     * <p>
272     * Sets the GUI element identifier.
273     * </p>
274     *
275     * @param indentifier
276     */
277    public void setIndex(int index) {
278        this.index = index;
279    }
280
281    /**
282     * Set the hash code associated with the GUI element.
283     *
284     * @param hash
285     *            the hash of an element object
286     */
287    public void setElementHash(int hash) {
288        this.elementHash = hash;
289    }
290
291    /**
292     * Set the path associated with the specified GUI element.
293     *
294     * @param path
295     *            the path to an element
296     */
297    public void setPath(String path) {
298        this.path = path;
299    }
300
301    /**
302     * <p>
303     * Sets the type of the specified GUI element.
304     * </p>
305     *
306     * @param type
307     *            the type
308     */
309    public void setType(String type) {
310        this.type = type;
311    }
312
313    /**
314     * <p>
315     * Sets the name of the specified GUI element. Displayed text in the application or image name.
316     * </p>
317     *
318     * @param name
319     *            the name
320     */
321    public void setName(String name) {
322        this.name = name;
323    }
324
325    /**
326     * <p>
327     * Sets the type hierarchy of the specified GUI element.
328     *
329     * @param typeHierarchy
330     *            </p>
331     */
332    public void setTypeHierarchy(List<String> typeHierarchy) {
333        this.typeHierarchy = typeHierarchy;
334    }
335
336    /*
337     * (non-Javadoc)
338     *
339     * @see de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElementSpec#equals(IGUIElementSpec)
340     */
341    @Override
342    public boolean equals(Object other) {
343        if (this == other) {
344            return true;
345        }
346
347        if (!(other instanceof ANDROIDGUIElementSpec)) {
348            return false;
349        }
350
351        ANDROIDGUIElementSpec otherSpec = (ANDROIDGUIElementSpec) other;
352
353        return (elementHash == otherSpec.elementHash) &&
354            (path == null ? otherSpec.path == null : path.equals(otherSpec.path)) &&
355            (index == otherSpec.index) &&
356            (elementPosition == otherSpec.elementPosition) &&
357            (name == null ? otherSpec.name == null : name.equals(otherSpec.name)) &&
358            (type == null ? otherSpec.type == null : type.equals(otherSpec.type));
359    }
360
361    /*
362     * (non-Javadoc)
363     *
364     * @see java.lang.Object#hashCode()
365     */
366    @Override
367    public int hashCode() {
368        // 17 due to the reason that this is a prime number.
369        int result = 17;
370        /*
371         * 31 due to the reason that a lot of VM's could optimize this multiplication by a shift.
372         * Source: Effective Java, Joshua Bloch, 2008, p.48
373         */
374        result = 31 * result + elementHash;
375        result = 31 * result + path.hashCode();
376        result = 31 * result + index;
377        result = 31 * result + getName().hashCode();
378        result = 31 * result + type.hashCode();
379        result = 31 * result + elementPosition;
380        return result;
381    }
382
383}
Note: See TracBrowser for help on using the repository browser.